diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
116 files changed, 25051 insertions, 17085 deletions
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index d491a3178986..0c47be06c153 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -1,8 +1,11 @@ +# SPDX-License-Identifier: ISC config ATH9K_HW tristate config ATH9K_COMMON tristate select ATH_COMMON +config ATH9K_COMMON_DEBUG + bool config ATH9K_DFS_DEBUGFS def_bool y depends on ATH9K_DEBUGFS && ATH9K_DFS_CERTIFIED @@ -11,19 +14,17 @@ config ATH9K_BTCOEX_SUPPORT bool "Atheros bluetooth coexistence support" depends on (ATH9K || ATH9K_HTC) default y - ---help--- + help Say Y, if you want to use the ath9k/ath9k_htc radios together with Bluetooth modules in the same system. config ATH9K tristate "Atheros 802.11n wireless cards support" depends on MAC80211 && HAS_DMA + select MAC80211_LEDS if LEDS_CLASS=y || LEDS_CLASS=MAC80211 select ATH9K_HW - select MAC80211_LEDS - select LEDS_CLASS - select NEW_LEDS select ATH9K_COMMON - ---help--- + help This module adds support for wireless adapters based on Atheros IEEE 802.11n AR5008, AR9001 and AR9002 family of chipsets. For a specific list of supported external @@ -31,7 +32,7 @@ config ATH9K APs that come with these cards refer to ath9k wiki products page: - http://wireless.kernel.org/en/users/Drivers/ath9k/products + https://wireless.wiki.kernel.org/en/users/Drivers/ath9k/products If you choose to build a module, it'll be called ath9k. @@ -39,7 +40,7 @@ config ATH9K_PCI bool "Atheros ath9k PCI/PCIe bus support" default y depends on ATH9K && PCI - ---help--- + help This option enables the PCI bus support in ath9k. Say Y, if you have a compatible PCI/PCIe wireless card. @@ -48,7 +49,7 @@ config ATH9K_AHB bool "Atheros ath9k AHB bus support" depends on ATH9K default n - ---help--- + help This option enables the AHB bus support in ath9k. Say Y, if you have a SoC with a compatible built-in @@ -56,20 +57,47 @@ config ATH9K_AHB config ATH9K_DEBUGFS bool "Atheros ath9k debugging" - depends on ATH9K - select MAC80211_DEBUGFS - select RELAY - ---help--- + depends on ATH9K && DEBUG_FS && MAC80211_DEBUGFS + select ATH9K_COMMON_DEBUG + help Say Y, if you need access to ath9k's statistics for interrupts, rate control, etc. - Also required for changing debug message flags at run time. + Also required for changing debug message flags at run time and for + TX99. + +config ATH9K_STATION_STATISTICS + bool "Detailed station statistics" + depends on ATH9K && ATH9K_DEBUGFS && DEBUG_FS + default n + help + This option enables detailed statistics for association stations. + +config ATH9K_TX99 + bool "Atheros ath9k TX99 testing support" + depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS + default n + help + Say N. This should only be enabled on systems undergoing + certification testing and evaluation in a controlled environment. + Enabling this will only enable TX99 support, all other modes of + operation will be disabled. + + TX99 support enables Specific Absorption Rate (SAR) testing. + SAR is the unit of measurement for the amount of radio frequency(RF) + absorbed by the body when using a wireless device. The RF exposure + limits used are expressed in the terms of SAR, which is a measure + of the electric and magnetic field strength and power density for + transmitters operating at frequencies from 300 kHz to 100 GHz. + Regulatory bodies around the world require that wireless device + be evaluated to meet the RF exposure limits set forth in the + governmental SAR regulations. config ATH9K_DFS_CERTIFIED bool "Atheros DFS support for certified platforms" depends on ATH9K && CFG80211_CERTIFICATION_ONUS default n - ---help--- + help This option enables DFS support for initiating radiation on ath9k. There is no way to dynamically detect if a card was DFS certified and as such this is left as a build time option. This @@ -84,36 +112,101 @@ config ATH9K_DFS_CERTIFIED developed. At this point enabling this option won't do anything except increase code size. -config ATH9K_LEGACY_RATE_CONTROL - bool "Atheros ath9k rate control" +config ATH9K_DYNACK + bool "Atheros ath9k ACK timeout estimation algorithm" + depends on ATH9K + default n + help + This option enables ath9k dynamic ACK timeout estimation algorithm + based on ACK frame RX timestamp, TX frame timestamp and frame + duration + +config ATH9K_WOW + bool "Wake on Wireless LAN support (EXPERIMENTAL)" + depends on ATH9K && PM + default n + help + This option enables Wake on Wireless LAN support for certain cards. + Currently, AR9462 is supported. + +config ATH9K_RFKILL + bool "Atheros ath9k rfkill support" if EXPERT + depends on ATH9K + depends on RFKILL=y || RFKILL=ATH9K + default y + help + Say Y to have ath9k poll the RF-Kill GPIO every couple of + seconds. Turn off to save power, but enable it if you have + a platform that can toggle the RF-Kill GPIO. + +config ATH9K_CHANNEL_CONTEXT + bool "Channel Context support" + depends on ATH9K + default n + help + This option enables channel context support in ath9k, which is needed + for multi-channel concurrency. Enable this if P2P PowerSave support + is required. + +config ATH9K_PCOEM + bool "Atheros ath9k support for PC OEM cards" if EXPERT depends on ATH9K + default y + +config ATH9K_PCI_NO_EEPROM + tristate "Atheros ath9k pci loader for EEPROM-less chips" + depends on ATH9K_PCI default n - ---help--- - Say Y, if you want to use the ath9k specific rate control - module instead of minstrel_ht. Be warned that there are various - issues with the ath9k RC and minstrel is a more robust algorithm. - Note that even if this option is selected, "ath9k_rate_control" - has to be passed to mac80211 using the module parameter, - ieee80211_default_rc_algo. + help + This separate driver provides a loader in order to support the + AR500X to AR92XX-generation of ath9k PCI(e) WiFi chips, which have + their initialization data (which contains the real PCI Device ID + that ath9k will need) stored together with the calibration data out + of reach for the ath9k chip. + + These devices are usually various network appliances, routers or + access Points and such. + + If unsure say N. config ATH9K_HTC - tristate "Atheros HTC based wireless cards support" - depends on USB && MAC80211 - select ATH9K_HW - select MAC80211_LEDS - select LEDS_CLASS - select NEW_LEDS - select ATH9K_COMMON - ---help--- - Support for Atheros HTC based cards. - Chipsets supported: AR9271 + tristate "Atheros HTC based wireless cards support" + depends on USB && MAC80211 + select MAC80211_LEDS if LEDS_CLASS=y || LEDS_CLASS=MAC80211 + select ATH9K_HW + select ATH9K_COMMON + help + Support for Atheros HTC based cards. + Chipsets supported: AR9271 - For more information: http://wireless.kernel.org/en/users/Drivers/ath9k_htc + For more information: + https://wireless.wiki.kernel.org/en/users/Drivers/ath9k_htc - The built module will be ath9k_htc. + The built module will be ath9k_htc. config ATH9K_HTC_DEBUGFS bool "Atheros ath9k_htc debugging" depends on ATH9K_HTC && DEBUG_FS - ---help--- + select ATH9K_COMMON_DEBUG + help Say Y, if you need access to ath9k_htc's statistics. + As well as access to the FFT/spectral data. + +config ATH9K_HWRNG + bool "Random number generator support" + depends on ATH9K && (HW_RANDOM = y || HW_RANDOM = ATH9K) + default n + help + This option incorporates the ADC register output as a source of + randomness into Linux entropy pool (/dev/urandom and /dev/random) + + Say Y, feeds the entropy directly from the WiFi driver to the input + pool. + +config ATH9K_COMMON_SPECTRAL + bool "Atheros ath9k/ath9k_htc spectral scan support" + depends on ATH9K_DEBUGFS || ATH9K_HTC_DEBUGFS + select RELAY + default n + help + Say Y to enable access to the FFT/spectral data via debugfs. diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 75ee9e7704ce..eff94bcd1f0a 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: ISC ath9k-y += beacon.o \ gpio.o \ init.o \ @@ -5,19 +6,21 @@ ath9k-y += beacon.o \ recv.o \ xmit.o \ link.o \ - antenna.o + antenna.o \ + channel.o ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o -ath9k-$(CONFIG_ATH9K_LEGACY_RATE_CONTROL) += rc.o ath9k-$(CONFIG_ATH9K_PCI) += pci.o ath9k-$(CONFIG_ATH9K_AHB) += ahb.o -ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o -ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += \ - dfs.o \ - dfs_pattern_detector.o \ - dfs_pri_detector.o -ath9k-$(CONFIG_PM_SLEEP) += wow.o +ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o +ath9k-$(CONFIG_ATH9K_TX99) += tx99.o +ath9k-$(CONFIG_ATH9K_WOW) += wow.o +ath9k-$(CONFIG_ATH9K_HWRNG) += rng.o + +ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o + +ath9k-$(CONFIG_ATH9K_STATION_STATISTICS) += debug_sta.o obj-$(CONFIG_ATH9K) += ath9k.o @@ -30,7 +33,6 @@ ath9k_hw-y:= \ ar5008_phy.o \ ar9002_calib.o \ ar9003_calib.o \ - ar9003_rtt.o \ calib.o \ eeprom.o \ eeprom_def.o \ @@ -43,12 +45,25 @@ ath9k_hw-y:= \ ar9003_eeprom.o \ ar9003_paprd.o +ath9k_hw-$(CONFIG_ATH9K_WOW) += ar9003_wow.o + ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \ - ar9003_mci.o + ar9003_mci.o \ + ar9003_aic.o + +ath9k_hw-$(CONFIG_ATH9K_PCOEM) += ar9003_rtt.o + +ath9k_hw-$(CONFIG_ATH9K_DYNACK) += dynack.o + obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o -ath9k_common-y:= common.o +ath9k_common-y:= common.o \ + common-init.o \ + common-beacon.o \ + +ath9k_common-$(CONFIG_ATH9K_COMMON_DEBUG) += common-debug.o +ath9k_common-$(CONFIG_ATH9K_COMMON_SPECTRAL) += common-spectral.o ath9k_htc-y += htc_hst.o \ hif_usb.o \ @@ -62,3 +77,5 @@ ath9k_htc-y += htc_hst.o \ ath9k_htc-$(CONFIG_ATH9K_HTC_DEBUGFS) += htc_drv_debug.o obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o + +obj-$(CONFIG_ATH9K_PCI_NO_EEPROM) += ath9k_pci_owl_loader.o diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 072e4b531067..802e6596a6a8 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -16,29 +16,21 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/mod_devicetable.h> +#include <linux/module.h> #include <linux/nl80211.h> +#include <linux/of.h> #include <linux/platform_device.h> -#include <linux/ath9k_platform.h> -#include <linux/module.h> + #include "ath9k.h" -static const struct platform_device_id ath9k_platform_id_table[] = { - { - .name = "ath9k", - .driver_data = AR5416_AR9100_DEVID, - }, - { - .name = "ar933x_wmac", - .driver_data = AR9300_DEVID_AR9330, - }, - { - .name = "ar934x_wmac", - .driver_data = AR9300_DEVID_AR9340, - }, - { - .name = "qca955x_wmac", - .driver_data = AR9300_DEVID_QCA955X, - }, +static const struct of_device_id ath9k_of_match_table[] = { + { .compatible = "qca,ar9130-wifi", .data = (void *)AR5416_AR9100_DEVID }, + { .compatible = "qca,ar9330-wifi", .data = (void *)AR9300_DEVID_AR9330 }, + { .compatible = "qca,ar9340-wifi", .data = (void *)AR9300_DEVID_AR9340 }, + { .compatible = "qca,qca9530-wifi", .data = (void *)AR9300_DEVID_AR953X }, + { .compatible = "qca,qca9550-wifi", .data = (void *)AR9300_DEVID_QCA955X }, + { .compatible = "qca,qca9560-wifi", .data = (void *)AR9300_DEVID_QCA956X }, {}, }; @@ -50,23 +42,12 @@ static void ath_ahb_read_cachesize(struct ath_common *common, int *csz) static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data) { - struct ath_softc *sc = (struct ath_softc *)common->priv; - struct platform_device *pdev = to_platform_device(sc->dev); - struct ath9k_platform_data *pdata; - - pdata = (struct ath9k_platform_data *) pdev->dev.platform_data; - if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { - ath_err(common, - "%s: flash read failed, offset %08x is out of range\n", - __func__, off); - return false; - } - - *data = pdata->eeprom_data[off]; - return true; + ath_err(common, "%s: eeprom data has to be provided externally\n", + __func__); + return false; } -static struct ath_bus_ops ath_ahb_bus_ops = { +static const struct ath_bus_ops ath_ahb_bus_ops = { .ath_bus_type = ATH_AHB, .read_cachesize = ath_ahb_read_cachesize, .eeprom_read = ath_ahb_eeprom_read, @@ -74,41 +55,26 @@ static struct ath_bus_ops ath_ahb_bus_ops = { static int ath_ahb_probe(struct platform_device *pdev) { - void __iomem *mem; - struct ath_softc *sc; struct ieee80211_hw *hw; - struct resource *res; - const struct platform_device_id *id = platform_get_device_id(pdev); - int irq; - int ret = 0; + struct ath_softc *sc; struct ath_hw *ah; + void __iomem *mem; char hw_name[64]; + u16 dev_id; + int irq; + int ret; - if (!pdev->dev.platform_data) { - dev_err(&pdev->dev, "no platform data specified\n"); - return -EINVAL; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "no memory resource found\n"); - return -ENXIO; - } - - mem = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); - if (mem == NULL) { + mem = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mem)) { dev_err(&pdev->dev, "ioremap failed\n"); - return -ENOMEM; + return PTR_ERR(mem); } - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res == NULL) { - dev_err(&pdev->dev, "no IRQ resource found\n"); - return -ENXIO; - } - - irq = res->start; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + ath9k_fill_chanctx_ops(); hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); if (hw == NULL) { dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); @@ -124,16 +90,14 @@ static int ath_ahb_probe(struct platform_device *pdev) sc->mem = mem; sc->irq = irq; - /* Will be cleared in ath9k_start() */ - set_bit(SC_OP_INVALID, &sc->sc_flags); - ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); goto err_free_hw; } - ret = ath9k_init_device(id->driver_data, sc, &ath_ahb_bus_ops); + dev_id = (u16)(kernel_ulong_t)of_device_get_match_data(&pdev->dev); + ret = ath9k_init_device(dev_id, sc, &ath_ahb_bus_ops); if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto err_irq; @@ -141,8 +105,8 @@ static int ath_ahb_probe(struct platform_device *pdev) ah = sc->sc_ah; ath9k_hw_name(ah, hw_name, sizeof(hw_name)); - wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n", - hw_name, (unsigned long)mem, irq); + wiphy_info(hw->wiphy, "%s mem=0x%p, irq=%d\n", + hw_name, mem, irq); return 0; @@ -153,7 +117,7 @@ static int ath_ahb_probe(struct platform_device *pdev) return ret; } -static int ath_ahb_remove(struct platform_device *pdev) +static void ath_ahb_remove(struct platform_device *pdev) { struct ieee80211_hw *hw = platform_get_drvdata(pdev); @@ -164,21 +128,18 @@ static int ath_ahb_remove(struct platform_device *pdev) free_irq(sc->irq, sc); ieee80211_free_hw(sc->hw); } - - return 0; } static struct platform_driver ath_ahb_driver = { - .probe = ath_ahb_probe, - .remove = ath_ahb_remove, - .driver = { - .name = "ath9k", - .owner = THIS_MODULE, + .probe = ath_ahb_probe, + .remove = ath_ahb_remove, + .driver = { + .name = "ath9k", + .of_match_table = ath9k_of_match_table, }, - .id_table = ath9k_platform_id_table, }; -MODULE_DEVICE_TABLE(platform, ath9k_platform_id_table); +MODULE_DEVICE_TABLE(of, ath9k_of_match_table); int ath_ahb_init(void) { diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 4994bea809eb..41d192709e8e 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -59,13 +59,13 @@ static const struct ani_ofdm_level_entry ofdm_level_table[] = { /* * MRC (Maximal Ratio Combining) has always been used with multi-antenna ofdm. * With OFDM for single stream you just add up all antenna inputs, you're - * only interested in what you get after FFT. Signal aligment is also not + * only interested in what you get after FFT. Signal alignment is also not * required for OFDM because any phase difference adds up in the frequency * domain. * * MRC requires extra work for use with CCK. You need to align the antenna * signals from the different antenna before you can add the signals together. - * You need aligment of signals as CCK is in time domain, so addition can cancel + * You need alignment of signals as CCK is in time domain, so addition can cancel * your signal completely if phase is 180 degrees (think of adding sine waves). * You also need to remove noise before the addition and this is where ANI * MRC CCK comes into play. One of the antenna inputs may be stronger but @@ -74,7 +74,7 @@ static const struct ani_ofdm_level_entry ofdm_level_table[] = { * Regardless of alignment in time, the antenna signals add constructively after * FFT and improve your reception. For more information: * - * http://en.wikipedia.org/wiki/Maximal-ratio_combining + * https://en.wikipedia.org/wiki/Maximal-ratio_combining */ struct ani_cck_level_entry { @@ -107,21 +107,27 @@ static const struct ani_cck_level_entry cck_level_table[] = { static void ath9k_hw_update_mibstats(struct ath_hw *ah, struct ath9k_mib_stats *stats) { - stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); - stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); - stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); - stats->rts_good += REG_READ(ah, AR_RTS_OK); - stats->beacons += REG_READ(ah, AR_BEACON_CNT); + u32 addr[5] = {AR_RTS_OK, AR_RTS_FAIL, AR_ACK_FAIL, + AR_FCS_FAIL, AR_BEACON_CNT}; + u32 data[5]; + + REG_READ_MULTI(ah, &addr[0], &data[0], 5); + /* AR_RTS_OK */ + stats->rts_good += data[0]; + /* AR_RTS_FAIL */ + stats->rts_bad += data[1]; + /* AR_ACK_FAIL */ + stats->ackrcv_bad += data[2]; + /* AR_FCS_FAIL */ + stats->fcs_bad += data[3]; + /* AR_BEACON_CNT */ + stats->beacons += data[4]; } static void ath9k_ani_restart(struct ath_hw *ah) { - struct ar5416AniState *aniState; - - if (!ah->curchan) - return; + struct ar5416AniState *aniState = &ah->ani; - aniState = &ah->ani; aniState->listenTime = 0; ENABLE_REGWRITE_BUFFER(ah); @@ -155,6 +161,9 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, ATH9K_ANI_RSSI_THR_LOW, ATH9K_ANI_RSSI_THR_HIGH); + if (AR_SREV_9100(ah) && immunityLevel < ATH9K_ANI_OFDM_DEF_LEVEL) + immunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL; + if (!scan) aniState->ofdmNoiseImmunityLevel = immunityLevel; @@ -176,16 +185,26 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, if (ah->opmode == NL80211_IFTYPE_STATION && BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH) weak_sig = true; - /* - * OFDM Weak signal detection is always enabled for AP mode. + * Newer chipsets are better at dealing with high PHY error counts - + * keep weak signal detection enabled when no RSSI threshold is + * available to determine if it is needed (mode != STA) */ - if (ah->opmode != NL80211_IFTYPE_AP && - aniState->ofdmWeakSigDetect != weak_sig) { - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - entry_ofdm->ofdm_weak_signal_on); - } + else if (AR_SREV_9300_20_OR_LATER(ah) && + ah->opmode != NL80211_IFTYPE_STATION) + weak_sig = true; + + /* Older chipsets are more sensitive to high PHY error counts */ + else if (!AR_SREV_9300_20_OR_LATER(ah) && + aniState->ofdmNoiseImmunityLevel >= 8) + weak_sig = false; + + if (aniState->ofdmWeakSigDetect != weak_sig) + ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + weak_sig); + + if (!AR_SREV_9300_20_OR_LATER(ah)) + return; if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) { ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; @@ -198,12 +217,7 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) { - struct ar5416AniState *aniState; - - if (!ah->curchan) - return; - - aniState = &ah->ani; + struct ar5416AniState *aniState = &ah->ani; if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL) ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false); @@ -225,6 +239,9 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel, BEACON_RSSI(ah), ATH9K_ANI_RSSI_THR_LOW, ATH9K_ANI_RSSI_THR_HIGH); + if (AR_SREV_9100(ah) && immunityLevel < ATH9K_ANI_CCK_DEF_LEVEL) + immunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; + if (ah->opmode == NL80211_IFTYPE_STATION && BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_LOW && immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI) @@ -243,7 +260,8 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel, entry_cck->fir_step_level); /* Skip MRC CCK for pre AR9003 families */ - if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) + if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah) || + AR_SREV_9565(ah) || AR_SREV_9561(ah)) return; if (aniState->mrcCCK != entry_cck->mrc_cck_on) @@ -254,12 +272,7 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel, static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) { - struct ar5416AniState *aniState; - - if (!ah->curchan) - return; - - aniState = &ah->ani; + struct ar5416AniState *aniState = &ah->ani; if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL) ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1, @@ -272,9 +285,7 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) */ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) { - struct ar5416AniState *aniState; - - aniState = &ah->ani; + struct ar5416AniState *aniState = &ah->ani; /* lower OFDM noise immunity */ if (aniState->ofdmNoiseImmunityLevel > 0 && @@ -302,26 +313,12 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) struct ath_common *common = ath9k_hw_common(ah); int ofdm_nil, cck_nil; - if (!ah->curchan) + if (!chan) return; BUG_ON(aniState == NULL); ah->stats.ast_ani_reset++; - /* only allow a subset of functions in AP mode */ - if (ah->opmode == NL80211_IFTYPE_AP) { - if (IS_CHAN_2GHZ(chan)) { - ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | - ATH9K_ANI_FIRSTEP_LEVEL); - if (AR_SREV_9300_20_OR_LATER(ah)) - ah->ani_function |= ATH9K_ANI_MRC_CCK; - } else - ah->ani_function = 0; - } - - /* always allow mode (on/off) to be controlled */ - ah->ani_function |= ATH9K_ANI_MODE; - ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL, aniState->ofdmNoiseImmunityLevel); cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL, @@ -341,10 +338,9 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) aniState->cckNoiseImmunityLevel != ATH9K_ANI_CCK_DEF_LEVEL) { ath_dbg(common, ANI, - "Restore defaults: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", + "Restore defaults: opmode %u chan %d Mhz is_scanning=%d ofdm:%d cck:%d\n", ah->opmode, chan->channel, - chan->channelFlags, is_scanning, aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); @@ -357,10 +353,9 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) * restore historical levels for this channel */ ath_dbg(common, ANI, - "Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n", + "Restore history: opmode %u chan %d Mhz is_scanning=%d ofdm:%d cck:%d\n", ah->opmode, chan->channel, - chan->channelFlags, is_scanning, aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); @@ -405,14 +400,10 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ar5416AniState *aniState; + struct ar5416AniState *aniState = &ah->ani; struct ath_common *common = ath9k_hw_common(ah); u32 ofdmPhyErrRate, cckPhyErrRate; - if (!ah->curchan) - return; - - aniState = &ah->ani; if (!ath9k_hw_ani_read_counters(ah)) return; @@ -439,7 +430,9 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) } else if (cckPhyErrRate > ah->config.cck_trig_high) { ath9k_hw_ani_cck_err_trigger(ah); aniState->ofdmsTurn = true; - } + } else + return; + ath9k_ani_restart(ah); } } @@ -488,10 +481,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ath_dbg(common, ANI, "Initialize ANI\n"); - ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; - ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; - ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; - ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; + if (AR_SREV_9300_20_OR_LATER(ah)) { + ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; + ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; + ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; + ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; + } else { + ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD; + ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD; + ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD; + ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD; + } ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index b54a3fb01883..c40965b4c1e2 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -22,12 +22,16 @@ /* units are errors per second */ #define ATH9K_ANI_OFDM_TRIG_HIGH 3500 #define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000 +#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD 500 #define ATH9K_ANI_OFDM_TRIG_LOW 400 #define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900 +#define ATH9K_ANI_OFDM_TRIG_LOW_OLD 200 #define ATH9K_ANI_CCK_TRIG_HIGH 600 +#define ATH9K_ANI_CCK_TRIG_HIGH_OLD 200 #define ATH9K_ANI_CCK_TRIG_LOW 300 +#define ATH9K_ANI_CCK_TRIG_LOW_OLD 100 #define ATH9K_ANI_SPUR_IMMUNE_LVL 3 #define ATH9K_ANI_FIRSTEP_LVL 2 @@ -48,15 +52,10 @@ /* values here are relative to the INI */ enum ath9k_ani_cmd { - ATH9K_ANI_PRESENT = 0x1, - ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION = 0x4, - ATH9K_ANI_CCK_WEAK_SIGNAL_THR = 0x8, - ATH9K_ANI_FIRSTEP_LEVEL = 0x10, - ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20, - ATH9K_ANI_MODE = 0x40, - ATH9K_ANI_PHYERR_RESET = 0x80, - ATH9K_ANI_MRC_CCK = 0x100, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION = 0x1, + ATH9K_ANI_FIRSTEP_LEVEL = 0x2, + ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x4, + ATH9K_ANI_MRC_CCK = 0x8, ATH9K_ANI_ALL = 0xfff }; diff --git a/drivers/net/wireless/ath/ath9k/antenna.c b/drivers/net/wireless/ath/ath9k/antenna.c index 664844c5d3d5..e5e274bc9e68 100644 --- a/drivers/net/wireless/ath/ath9k/antenna.c +++ b/drivers/net/wireless/ath/ath9k/antenna.c @@ -16,37 +16,119 @@ #include "ath9k.h" -static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta, +/* + * AR9285 + * ====== + * + * EEPROM has 2 4-bit fields containing the card configuration. + * + * antdiv_ctl1: + * ------------ + * bb_enable_ant_div_lnadiv : 1 + * bb_ant_div_alt_gaintb : 1 + * bb_ant_div_main_gaintb : 1 + * bb_enable_ant_fast_div : 1 + * + * antdiv_ctl2: + * ----------- + * bb_ant_div_alt_lnaconf : 2 + * bb_ant_div_main_lnaconf : 2 + * + * The EEPROM bits are used as follows: + * ------------------------------------ + * + * bb_enable_ant_div_lnadiv - Enable LNA path rx antenna diversity/combining. + * Set in AR_PHY_MULTICHAIN_GAIN_CTL. + * + * bb_ant_div_[alt/main]_gaintb - 0 -> Antenna config Alt/Main uses gaintable 0 + * 1 -> Antenna config Alt/Main uses gaintable 1 + * Set in AR_PHY_MULTICHAIN_GAIN_CTL. + * + * bb_enable_ant_fast_div - Enable fast antenna diversity. + * Set in AR_PHY_CCK_DETECT. + * + * bb_ant_div_[alt/main]_lnaconf - Alt/Main LNA diversity/combining input config. + * Set in AR_PHY_MULTICHAIN_GAIN_CTL. + * 10=LNA1 + * 01=LNA2 + * 11=LNA1+LNA2 + * 00=LNA1-LNA2 + * + * AR9485 / AR9565 / AR9331 + * ======================== + * + * The same bits are present in the EEPROM, but the location in the + * EEPROM is different (ant_div_control in ar9300_BaseExtension_1). + * + * ant_div_alt_lnaconf ==> bit 0~1 + * ant_div_main_lnaconf ==> bit 2~3 + * ant_div_alt_gaintb ==> bit 4 + * ant_div_main_gaintb ==> bit 5 + * enable_ant_div_lnadiv ==> bit 6 + * enable_ant_fast_div ==> bit 7 + */ + +static inline bool ath_is_alt_ant_ratio_better(struct ath_ant_comb *antcomb, + int alt_ratio, int maxdelta, int mindelta, int main_rssi_avg, int alt_rssi_avg, int pkt_count) { - return (((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && - (alt_rssi_avg > main_rssi_avg + maxdelta)) || - (alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50); + if (pkt_count <= 50) + return false; + + if (alt_rssi_avg > main_rssi_avg + mindelta) + return true; + + if (alt_ratio >= antcomb->ant_ratio2 && + alt_rssi_avg >= antcomb->low_rssi_thresh && + (alt_rssi_avg > main_rssi_avg + maxdelta)) + return true; + + return false; } -static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio, - int curr_main_set, int curr_alt_set, - int alt_rssi_avg, int main_rssi_avg) +static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf *conf, + struct ath_ant_comb *antcomb, + int alt_ratio, int alt_rssi_avg, + int main_rssi_avg) { - bool result = false; - switch (div_group) { + bool result, set1, set2; + + result = set1 = set2 = false; + + if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2 && + conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA1) + set1 = true; + + if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA1 && + conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA2) + set2 = true; + + switch (conf->div_group) { case 0: if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) result = true; break; case 1: case 2: - if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) && - (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) && - (alt_rssi_avg >= (main_rssi_avg - 5))) || - ((curr_main_set == ATH_ANT_DIV_COMB_LNA1) && - (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) && - (alt_rssi_avg >= (main_rssi_avg - 2)))) && - (alt_rssi_avg >= 4)) + if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh) + break; + + if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 5))) || + (set2 && (alt_rssi_avg >= (main_rssi_avg - 2))) || + (alt_ratio > antcomb->ant_ratio)) result = true; - else - result = false; + + break; + case 3: + if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh) + break; + + if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 3))) || + (set2 && (alt_rssi_avg >= (main_rssi_avg + 3))) || + (alt_ratio > antcomb->ant_ratio)) + result = true; + break; } @@ -108,6 +190,74 @@ static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb, } } +static void ath_ant_set_alt_ratio(struct ath_ant_comb *antcomb, + struct ath_hw_antcomb_conf *conf) +{ + /* set alt to the conf with maximum ratio */ + if (antcomb->first_ratio && antcomb->second_ratio) { + if (antcomb->rssi_second > antcomb->rssi_third) { + /* first alt*/ + if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) || + (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) + /* Set alt LNA1 or LNA2*/ + if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + else + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + else + /* Set alt to A+B or A-B */ + conf->alt_lna_conf = + antcomb->first_quick_scan_conf; + } else if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) || + (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) { + /* Set alt LNA1 or LNA2 */ + if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + else + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + } else { + /* Set alt to A+B or A-B */ + conf->alt_lna_conf = antcomb->second_quick_scan_conf; + } + } else if (antcomb->first_ratio) { + /* first alt */ + if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) || + (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) + /* Set alt LNA1 or LNA2 */ + if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + else + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + else + /* Set alt to A+B or A-B */ + conf->alt_lna_conf = antcomb->first_quick_scan_conf; + } else if (antcomb->second_ratio) { + /* second alt */ + if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) || + (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) + /* Set alt LNA1 or LNA2 */ + if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + else + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + else + /* Set alt to A+B or A-B */ + conf->alt_lna_conf = antcomb->second_quick_scan_conf; + } else { + /* main is largest */ + if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) || + (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)) + /* Set alt LNA1 or LNA2 */ + if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2) + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + else + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + else + /* Set alt to A+B or A-B */ + conf->alt_lna_conf = antcomb->main_conf; + } +} + static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, struct ath_hw_antcomb_conf *div_ant_conf, int main_rssi_avg, int alt_rssi_avg, @@ -129,7 +279,7 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) { /* main is LNA1 */ - if (ath_is_alt_ant_ratio_better(alt_ratio, + if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, ATH_ANT_DIV_COMB_LNA1_DELTA_HI, ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, main_rssi_avg, alt_rssi_avg, @@ -138,7 +288,7 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, else antcomb->first_ratio = false; } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) { - if (ath_is_alt_ant_ratio_better(alt_ratio, + if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, ATH_ANT_DIV_COMB_LNA1_DELTA_MID, ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, main_rssi_avg, alt_rssi_avg, @@ -147,11 +297,11 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, else antcomb->first_ratio = false; } else { - if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && - (alt_rssi_avg > main_rssi_avg + - ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) || - (alt_rssi_avg > main_rssi_avg)) && - (antcomb->total_pkt_count > 50)) + if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, + ATH_ANT_DIV_COMB_LNA1_DELTA_HI, + 0, + main_rssi_avg, alt_rssi_avg, + antcomb->total_pkt_count)) antcomb->first_ratio = true; else antcomb->first_ratio = false; @@ -164,27 +314,31 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, antcomb->rssi_first = main_rssi_avg; antcomb->rssi_third = alt_rssi_avg; - if (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) + switch(antcomb->second_quick_scan_conf) { + case ATH_ANT_DIV_COMB_LNA1: antcomb->rssi_lna1 = alt_rssi_avg; - else if (antcomb->second_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA2) + break; + case ATH_ANT_DIV_COMB_LNA2: antcomb->rssi_lna2 = alt_rssi_avg; - else if (antcomb->second_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) { + break; + case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2: if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) antcomb->rssi_lna2 = main_rssi_avg; else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) antcomb->rssi_lna1 = main_rssi_avg; + break; + default: + break; } if (antcomb->rssi_lna2 > antcomb->rssi_lna1 + - ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA) + div_ant_conf->lna1_lna2_switch_delta) div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; else div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) { - if (ath_is_alt_ant_ratio_better(alt_ratio, + if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, ATH_ANT_DIV_COMB_LNA1_DELTA_HI, ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, main_rssi_avg, alt_rssi_avg, @@ -193,7 +347,7 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, else antcomb->second_ratio = false; } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) { - if (ath_is_alt_ant_ratio_better(alt_ratio, + if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, ATH_ANT_DIV_COMB_LNA1_DELTA_MID, ATH_ANT_DIV_COMB_LNA1_DELTA_LOW, main_rssi_avg, alt_rssi_avg, @@ -202,105 +356,18 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb, else antcomb->second_ratio = false; } else { - if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) && - (alt_rssi_avg > main_rssi_avg + - ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) || - (alt_rssi_avg > main_rssi_avg)) && - (antcomb->total_pkt_count > 50)) + if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio, + ATH_ANT_DIV_COMB_LNA1_DELTA_HI, + 0, + main_rssi_avg, alt_rssi_avg, + antcomb->total_pkt_count)) antcomb->second_ratio = true; else antcomb->second_ratio = false; } - /* set alt to the conf with maximun ratio */ - if (antcomb->first_ratio && antcomb->second_ratio) { - if (antcomb->rssi_second > antcomb->rssi_third) { - /* first alt*/ - if ((antcomb->first_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA1) || - (antcomb->first_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA2)) - /* Set alt LNA1 or LNA2*/ - if (div_ant_conf->main_lna_conf == - ATH_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - else - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = - antcomb->first_quick_scan_conf; - } else if ((antcomb->second_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA1) || - (antcomb->second_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA2)) { - /* Set alt LNA1 or LNA2 */ - if (div_ant_conf->main_lna_conf == - ATH_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - } else { - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = - antcomb->second_quick_scan_conf; - } - } else if (antcomb->first_ratio) { - /* first alt */ - if ((antcomb->first_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA1) || - (antcomb->first_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA2)) - /* Set alt LNA1 or LNA2 */ - if (div_ant_conf->main_lna_conf == - ATH_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - else - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = - antcomb->first_quick_scan_conf; - } else if (antcomb->second_ratio) { - /* second alt */ - if ((antcomb->second_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA1) || - (antcomb->second_quick_scan_conf == - ATH_ANT_DIV_COMB_LNA2)) - /* Set alt LNA1 or LNA2 */ - if (div_ant_conf->main_lna_conf == - ATH_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - else - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = - antcomb->second_quick_scan_conf; - } else { - /* main is largest */ - if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) || - (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)) - /* Set alt LNA1 or LNA2 */ - if (div_ant_conf->main_lna_conf == - ATH_ANT_DIV_COMB_LNA2) - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - else - div_ant_conf->alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - else - /* Set alt to A+B or A-B */ - div_ant_conf->alt_lna_conf = antcomb->main_conf; - } + ath_ant_set_alt_ratio(antcomb, div_ant_conf); + break; default: break; @@ -430,8 +497,7 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x1; break; case 0x10: /* LNA2 A-B */ - if (!(antcomb->scan) && - (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio)) ant_conf->fast_div_bias = 0x1; else ant_conf->fast_div_bias = 0x2; @@ -440,15 +506,13 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x1; break; case 0x13: /* LNA2 A+B */ - if (!(antcomb->scan) && - (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio)) ant_conf->fast_div_bias = 0x1; else ant_conf->fast_div_bias = 0x2; break; case 0x20: /* LNA1 A-B */ - if (!(antcomb->scan) && - (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio)) ant_conf->fast_div_bias = 0x1; else ant_conf->fast_div_bias = 0x2; @@ -457,8 +521,7 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x1; break; case 0x23: /* LNA1 A+B */ - if (!(antcomb->scan) && - (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) + if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio)) ant_conf->fast_div_bias = 0x1; else ant_conf->fast_div_bias = 0x2; @@ -475,6 +538,9 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, default: break; } + + if (antcomb->fast_div_bias) + ant_conf->fast_div_bias = antcomb->fast_div_bias; } else if (ant_conf->div_group == 3) { switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) { @@ -488,42 +554,22 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, ant_conf->fast_div_bias = 0x1; break; case 0x10: /* LNA2 A-B */ - if ((antcomb->scan == 0) && - (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { - ant_conf->fast_div_bias = 0x3f; - } else { - ant_conf->fast_div_bias = 0x1; - } + ant_conf->fast_div_bias = 0x2; break; case 0x12: /* LNA2 LNA1 */ - ant_conf->fast_div_bias = 0x39; + ant_conf->fast_div_bias = 0x3f; break; case 0x13: /* LNA2 A+B */ - if ((antcomb->scan == 0) && - (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { - ant_conf->fast_div_bias = 0x3f; - } else { - ant_conf->fast_div_bias = 0x1; - } + ant_conf->fast_div_bias = 0x2; break; case 0x20: /* LNA1 A-B */ - if ((antcomb->scan == 0) && - (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { - ant_conf->fast_div_bias = 0x3f; - } else { - ant_conf->fast_div_bias = 0x4; - } + ant_conf->fast_div_bias = 0x3; break; case 0x21: /* LNA1 LNA2 */ - ant_conf->fast_div_bias = 0x6; + ant_conf->fast_div_bias = 0x3; break; case 0x23: /* LNA1 A+B */ - if ((antcomb->scan == 0) && - (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { - ant_conf->fast_div_bias = 0x3f; - } else { - ant_conf->fast_div_bias = 0x6; - } + ant_conf->fast_div_bias = 0x3; break; case 0x30: /* A+B A-B */ ant_conf->fast_div_bias = 0x1; @@ -540,50 +586,187 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, } } +static void ath_ant_try_scan(struct ath_ant_comb *antcomb, + struct ath_hw_antcomb_conf *conf, + int curr_alt_set, int alt_rssi_avg, + int main_rssi_avg) +{ + switch (curr_alt_set) { + case ATH_ANT_DIV_COMB_LNA2: + antcomb->rssi_lna2 = alt_rssi_avg; + antcomb->rssi_lna1 = main_rssi_avg; + antcomb->scan = true; + /* set to A+B */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; + break; + case ATH_ANT_DIV_COMB_LNA1: + antcomb->rssi_lna1 = alt_rssi_avg; + antcomb->rssi_lna2 = main_rssi_avg; + antcomb->scan = true; + /* set to A+B */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; + break; + case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2: + antcomb->rssi_add = alt_rssi_avg; + antcomb->scan = true; + /* set to A-B */ + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; + break; + case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2: + antcomb->rssi_sub = alt_rssi_avg; + antcomb->scan = false; + if (antcomb->rssi_lna2 > + (antcomb->rssi_lna1 + conf->lna1_lna2_switch_delta)) { + /* use LNA2 as main LNA */ + if ((antcomb->rssi_add > antcomb->rssi_lna1) && + (antcomb->rssi_add > antcomb->rssi_sub)) { + /* set to A+B */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; + } else if (antcomb->rssi_sub > + antcomb->rssi_lna1) { + /* set to A-B */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; + } else { + /* set to LNA1 */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + } + } else { + /* use LNA1 as main LNA */ + if ((antcomb->rssi_add > antcomb->rssi_lna2) && + (antcomb->rssi_add > antcomb->rssi_sub)) { + /* set to A+B */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; + } else if (antcomb->rssi_sub > + antcomb->rssi_lna2) { + /* set to A-B */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; + } else { + /* set to LNA2 */ + conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; + conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + } + } + break; + default: + break; + } +} + +static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf, + struct ath_ant_comb *antcomb, + int alt_ratio, int alt_rssi_avg, + int main_rssi_avg, int curr_main_set, + int curr_alt_set) +{ + bool ret = false; + + if (ath_ant_div_comb_alt_check(div_ant_conf, antcomb, alt_ratio, + alt_rssi_avg, main_rssi_avg)) { + if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) { + /* + * Switch main and alt LNA. + */ + div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2; + div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) { + div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; + div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + } + + ret = true; + } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) && + (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) { + /* + Set alt to another LNA. + */ + if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) + div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1; + else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) + div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2; + + ret = true; + } + + return ret; +} + +static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb) +{ + int alt_ratio; + + if (!antcomb->scan || !antcomb->alt_good) + return false; + + if (time_after(jiffies, antcomb->scan_start_time + + msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR))) + return true; + + if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) { + alt_ratio = ((antcomb->alt_recv_cnt * 100) / + antcomb->total_pkt_count); + if (alt_ratio < antcomb->ant_ratio) + return true; + } + + return false; +} + void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) { struct ath_hw_antcomb_conf div_ant_conf; struct ath_ant_comb *antcomb = &sc->ant_comb; int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set; int curr_main_set; - int main_rssi = rs->rs_rssi_ctl0; - int alt_rssi = rs->rs_rssi_ctl1; + int main_rssi = rs->rs_rssi_ctl[0]; + int alt_rssi = rs->rs_rssi_ctl[1]; int rx_ant_conf, main_ant_conf; - bool short_scan = false; + bool short_scan = false, ret; - rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) & + rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) & ATH_ANT_RX_MASK; - main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) & + main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) & ATH_ANT_RX_MASK; + if (alt_rssi >= antcomb->low_rssi_thresh) { + antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO; + antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2; + } else { + antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI; + antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI; + } + /* Record packet only when both main_rssi and alt_rssi is positive */ if (main_rssi > 0 && alt_rssi > 0) { antcomb->total_pkt_count++; antcomb->main_total_rssi += main_rssi; antcomb->alt_total_rssi += alt_rssi; + if (main_ant_conf == rx_ant_conf) antcomb->main_recv_cnt++; else antcomb->alt_recv_cnt++; } - /* Short scan check */ - if (antcomb->scan && antcomb->alt_good) { - if (time_after(jiffies, antcomb->scan_start_time + - msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR))) - short_scan = true; - else - if (antcomb->total_pkt_count == - ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) { - alt_ratio = ((antcomb->alt_recv_cnt * 100) / - antcomb->total_pkt_count); - if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO) - short_scan = true; - } + if (main_ant_conf == rx_ant_conf) { + ANT_STAT_INC(sc, ANT_MAIN, recv_cnt); + ANT_LNA_INC(sc, ANT_MAIN, rx_ant_conf); + } else { + ANT_STAT_INC(sc, ANT_ALT, recv_cnt); + ANT_LNA_INC(sc, ANT_ALT, rx_ant_conf); } + /* Short scan check */ + short_scan = ath_ant_short_scan_check(antcomb); + if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) || - rs->rs_moreaggr) && !short_scan) + rs->rs_moreaggr) && !short_scan) return; if (antcomb->total_pkt_count) { @@ -595,15 +778,13 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) antcomb->total_pkt_count); } - ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf); curr_alt_set = div_ant_conf.alt_lna_conf; curr_main_set = div_ant_conf.main_lna_conf; - antcomb->count++; if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) { - if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { + if (alt_ratio > antcomb->ant_ratio) { ath_lnaconf_alt_good_scan(antcomb, div_ant_conf, main_rssi_avg); antcomb->alt_good = true; @@ -617,153 +798,47 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) } if (!antcomb->scan) { - if (ath_ant_div_comb_alt_check(div_ant_conf.div_group, - alt_ratio, curr_main_set, curr_alt_set, - alt_rssi_avg, main_rssi_avg)) { - if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) { - /* Switch main and alt LNA */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) { - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - } - - goto div_comb_done; - } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) && - (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) { - /* Set alt to another LNA */ - if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - - goto div_comb_done; - } - - if ((alt_rssi_avg < (main_rssi_avg + - div_ant_conf.lna1_lna2_delta))) + ret = ath_ant_try_switch(&div_ant_conf, antcomb, alt_ratio, + alt_rssi_avg, main_rssi_avg, + curr_main_set, curr_alt_set); + if (ret) goto div_comb_done; } + if (!antcomb->scan && + (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta))) + goto div_comb_done; + if (!antcomb->scan_not_start) { - switch (curr_alt_set) { - case ATH_ANT_DIV_COMB_LNA2: - antcomb->rssi_lna2 = alt_rssi_avg; - antcomb->rssi_lna1 = main_rssi_avg; - antcomb->scan = true; - /* set to A+B */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; - break; - case ATH_ANT_DIV_COMB_LNA1: - antcomb->rssi_lna1 = alt_rssi_avg; - antcomb->rssi_lna2 = main_rssi_avg; - antcomb->scan = true; - /* set to A+B */ - div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; - break; - case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2: - antcomb->rssi_add = alt_rssi_avg; - antcomb->scan = true; - /* set to A-B */ - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; - break; - case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2: - antcomb->rssi_sub = alt_rssi_avg; - antcomb->scan = false; - if (antcomb->rssi_lna2 > - (antcomb->rssi_lna1 + - ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) { - /* use LNA2 as main LNA */ - if ((antcomb->rssi_add > antcomb->rssi_lna1) && - (antcomb->rssi_add > antcomb->rssi_sub)) { - /* set to A+B */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; - } else if (antcomb->rssi_sub > - antcomb->rssi_lna1) { - /* set to A-B */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; - } else { - /* set to LNA1 */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - } - } else { - /* use LNA1 as main LNA */ - if ((antcomb->rssi_add > antcomb->rssi_lna2) && - (antcomb->rssi_add > antcomb->rssi_sub)) { - /* set to A+B */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; - } else if (antcomb->rssi_sub > - antcomb->rssi_lna1) { - /* set to A-B */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; - } else { - /* set to LNA2 */ - div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA1; - div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; - } - } - break; - default: - break; - } + ath_ant_try_scan(antcomb, &div_ant_conf, curr_alt_set, + alt_rssi_avg, main_rssi_avg); } else { if (!antcomb->alt_good) { antcomb->scan_not_start = false; /* Set alt to another LNA */ if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) { div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA2; + ATH_ANT_DIV_COMB_LNA2; div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA1; + ATH_ANT_DIV_COMB_LNA1; } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) { div_ant_conf.main_lna_conf = - ATH_ANT_DIV_COMB_LNA1; + ATH_ANT_DIV_COMB_LNA1; div_ant_conf.alt_lna_conf = - ATH_ANT_DIV_COMB_LNA2; + ATH_ANT_DIV_COMB_LNA2; } goto div_comb_done; } + ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf, + main_rssi_avg, alt_rssi_avg, + alt_ratio); + antcomb->quick_scan_cnt++; } - ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf, - main_rssi_avg, alt_rssi_avg, - alt_ratio); - - antcomb->quick_scan_cnt++; - div_comb_done: ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio); ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf); + ath9k_debug_stat_ant(sc, &div_ant_conf, main_rssi_avg, alt_rssi_avg); antcomb->scan_start_time = jiffies; antcomb->total_pkt_count = 0; @@ -772,26 +847,3 @@ div_comb_done: antcomb->main_recv_cnt = 0; antcomb->alt_recv_cnt = 0; } - -void ath_ant_comb_update(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - struct ath_hw_antcomb_conf div_ant_conf; - u8 lna_conf; - - ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf); - - if (sc->ant_rx == 1) - lna_conf = ATH_ANT_DIV_COMB_LNA1; - else - lna_conf = ATH_ANT_DIV_COMB_LNA2; - - div_ant_conf.main_lna_conf = lna_conf; - div_ant_conf.alt_lna_conf = lna_conf; - - ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf); - - if (common->antenna_diversity) - ath9k_hw_antctrl_shared_chain_lnadiv(ah, true); -} diff --git a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h index 467ccfae2cee..7da8365ae69a 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h @@ -459,12 +459,6 @@ static const u32 ar5416Common[][2] = { {0x0000a3e0, 0x000001ce}, }; -static const u32 ar5416Bank0[][2] = { - /* Addr allmodes */ - {0x000098b0, 0x1e5795e5}, - {0x000098e0, 0x02008020}, -}; - static const u32 ar5416BB_RfGain[][3] = { /* Addr 5G 2G */ {0x00009a00, 0x00000000, 0x00000000}, @@ -533,60 +527,6 @@ static const u32 ar5416BB_RfGain[][3] = { {0x00009afc, 0x000000f9, 0x000000f9}, }; -static const u32 ar5416Bank1[][2] = { - /* Addr allmodes */ - {0x000098b0, 0x02108421}, - {0x000098ec, 0x00000008}, -}; - -static const u32 ar5416Bank2[][2] = { - /* Addr allmodes */ - {0x000098b0, 0x0e73ff17}, - {0x000098e0, 0x00000420}, -}; - -static const u32 ar5416Bank3[][3] = { - /* Addr 5G 2G */ - {0x000098f0, 0x01400018, 0x01c00018}, -}; - -static const u32 ar5416Bank6[][3] = { - /* Addr 5G 2G */ - {0x0000989c, 0x00000000, 0x00000000}, - {0x0000989c, 0x00000000, 0x00000000}, - {0x0000989c, 0x00000000, 0x00000000}, - {0x0000989c, 0x00e00000, 0x00e00000}, - {0x0000989c, 0x005e0000, 0x005e0000}, - {0x0000989c, 0x00120000, 0x00120000}, - {0x0000989c, 0x00620000, 0x00620000}, - {0x0000989c, 0x00020000, 0x00020000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x40ff0000, 0x40ff0000}, - {0x0000989c, 0x005f0000, 0x005f0000}, - {0x0000989c, 0x00870000, 0x00870000}, - {0x0000989c, 0x00f90000, 0x00f90000}, - {0x0000989c, 0x007b0000, 0x007b0000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x00f50000, 0x00f50000}, - {0x0000989c, 0x00dc0000, 0x00dc0000}, - {0x0000989c, 0x00110000, 0x00110000}, - {0x0000989c, 0x006100a8, 0x006100a8}, - {0x0000989c, 0x004210a2, 0x004210a2}, - {0x0000989c, 0x0014008f, 0x0014008f}, - {0x0000989c, 0x00c40003, 0x00c40003}, - {0x0000989c, 0x003000f2, 0x003000f2}, - {0x0000989c, 0x00440016, 0x00440016}, - {0x0000989c, 0x00410040, 0x00410040}, - {0x0000989c, 0x0001805e, 0x0001805e}, - {0x0000989c, 0x0000c0ab, 0x0000c0ab}, - {0x0000989c, 0x000000f1, 0x000000f1}, - {0x0000989c, 0x00002081, 0x00002081}, - {0x0000989c, 0x000000d4, 0x000000d4}, - {0x000098d0, 0x0000000f, 0x0010000f}, -}; - static const u32 ar5416Bank6TPC[][3] = { /* Addr 5G 2G */ {0x0000989c, 0x00000000, 0x00000000}, @@ -624,13 +564,6 @@ static const u32 ar5416Bank6TPC[][3] = { {0x000098d0, 0x0000000f, 0x0010000f}, }; -static const u32 ar5416Bank7[][2] = { - /* Addr allmodes */ - {0x0000989c, 0x00000500}, - {0x0000989c, 0x00000800}, - {0x000098cc, 0x0000000e}, -}; - static const u32 ar5416Addac[][2] = { /* Addr allmodes */ {0x0000989c, 0x00000000}, @@ -671,4 +604,3 @@ static const u32 ar5416Addac[][2] = { {0x0000989c, 0x00000000}, {0x000098c4, 0x00000000}, }; - diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index d1acfe98918a..7a45f5f62826 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -18,17 +18,23 @@ #include "hw-ops.h" #include "../regd.h" #include "ar9002_phy.h" -#include "ar5008_initvals.h" /* All code below is for AR5008, AR9001, AR9002 */ -static const int firstep_table[] = -/* level: 0 1 2 3 4 5 6 7 8 */ - { -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */ +#define AR5008_OFDM_RATES 8 +#define AR5008_HT_SS_RATES 8 +#define AR5008_HT_DS_RATES 8 -static const int cycpwrThr1_table[] = -/* level: 0 1 2 3 4 5 6 7 8 */ - { -6, -4, -2, 0, 2, 4, 6, 8 }; /* lvl 0-7, default 3 */ +#define AR5008_HT20_SHIFT 16 +#define AR5008_HT40_SHIFT 24 + +#define AR5008_11NA_OFDM_SHIFT 0 +#define AR5008_11NA_HT_SS_SHIFT 8 +#define AR5008_11NA_HT_DS_SHIFT 16 + +#define AR5008_11NG_OFDM_SHIFT 4 +#define AR5008_11NG_HT_SS_SHIFT 12 +#define AR5008_11NG_HT_DS_SHIFT 20 /* * register values to turn OFDM weak signal detection OFF @@ -44,6 +50,36 @@ static const int m2ThreshLowExt_off = 127; static const int m1ThreshExt_off = 127; static const int m2ThreshExt_off = 127; +static const u32 ar5416Bank0[][2] = { + /* Addr allmodes */ + {0x000098b0, 0x1e5795e5}, + {0x000098e0, 0x02008020}, +}; + +static const u32 ar5416Bank1[][2] = { + /* Addr allmodes */ + {0x000098b0, 0x02108421}, + {0x000098ec, 0x00000008}, +}; + +static const u32 ar5416Bank2[][2] = { + /* Addr allmodes */ + {0x000098b0, 0x0e73ff17}, + {0x000098e0, 0x00000420}, +}; + +static const u32 ar5416Bank3[][3] = { + /* Addr 5G 2G */ + {0x000098f0, 0x01400018, 0x01c00018}, +}; + +static const u32 ar5416Bank7[][2] = { + /* Addr allmodes */ + {0x0000989c, 0x00000500}, + {0x0000989c, 0x00000800}, + {0x000098cc, 0x0000000e}, +}; + static const struct ar5416IniArray bank0 = STATIC_INI_ARRAY(ar5416Bank0); static const struct ar5416IniArray bank1 = STATIC_INI_ARRAY(ar5416Bank1); static const struct ar5416IniArray bank2 = STATIC_INI_ARRAY(ar5416Bank2); @@ -66,13 +102,8 @@ static void ar5008_write_bank6(struct ath_hw *ah, unsigned int *writecnt) REGWRITE_BUFFER_FLUSH(ah); } -/** +/* * ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters - * @rfbuf: - * @reg32: - * @numBits: - * @firstBit: - * @column: * * Performs analog "swizzling" of parameters into their location. * Used on external AR2133/AR5133 radios. @@ -162,10 +193,8 @@ static void ar5008_hw_force_bias(struct ath_hw *ah, u16 synth_freq) ar5008_write_bank6(ah, ®_writes); } -/** +/* * ar5008_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios - * @ah: atheros hardware structure - * @chan: * * For the external AR2133/AR5133 radios, takes the MHz channel value and set * the channel value. Assumes writes enabled to analog bus and bank6 register @@ -243,86 +272,25 @@ static int ar5008_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) return 0; } -/** - * ar5008_hw_spur_mitigate - convert baseband spur frequency for external radios - * @ah: atheros hardware structure - * @chan: - * - * For non single-chip solutions. Converts to baseband spur frequency given the - * input channel frequency and compute register settings below. - */ -static void ar5008_hw_spur_mitigate(struct ath_hw *ah, - struct ath9k_channel *chan) +void ar5008_hw_cmn_spur_mitigate(struct ath_hw *ah, + struct ath9k_channel *chan, int bin) { - int bb_spur = AR_NO_SPUR; - int bin, cur_bin; - int spur_freq_sd; - int spur_delta_phase; - int denominator; + int cur_bin; int upper, lower, cur_vit_mask; - int tmp, new; int i; - static int pilot_mask_reg[4] = { + int8_t mask_m[123] = {0}; + int8_t mask_p[123] = {0}; + int8_t mask_amt; + int tmp_mask; + static const int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 }; - static int chan_mask_reg[4] = { + static const int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 }; - static int inc[4] = { 0, 100, 0, 0 }; - - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; - int cur_bb_spur; - bool is2GHz = IS_CHAN_2GHZ(chan); - - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); - if (AR_NO_SPUR == cur_bb_spur) - break; - cur_bb_spur = cur_bb_spur - (chan->channel * 10); - if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { - bb_spur = cur_bb_spur; - break; - } - } - - if (AR_NO_SPUR == bb_spur) - return; - - bin = bb_spur * 32; - - tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); - new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | - AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | - AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | - AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); - - new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | - AR_PHY_SPUR_REG_ENABLE_MASK_PPM | - AR_PHY_SPUR_REG_MASK_RATE_SELECT | - AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | - SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); - REG_WRITE(ah, AR_PHY_SPUR_REG, new); - - spur_delta_phase = ((bb_spur * 524288) / 100) & - AR_PHY_TIMING11_SPUR_DELTA_PHASE; - - denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; - spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; - - new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | - SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | - SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); - REG_WRITE(ah, AR_PHY_TIMING11, new); + static const int inc[4] = { 0, 100, 0, 0 }; cur_bin = -6000; upper = bin + 100; @@ -332,6 +300,7 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah, int pilot_mask = 0; int chan_mask = 0; int bp = 0; + for (bp = 0; bp < 30; bp++) { if ((cur_bin > lower) && (cur_bin < upper)) { pilot_mask = pilot_mask | 0x1 << bp; @@ -348,9 +317,8 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah, upper = bin + 120; lower = bin - 120; - for (i = 0; i < 123; i++) { + for (i = 0; i < ARRAY_SIZE(mask_m); i++) { if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - /* workaround for gcc bug #37014 */ volatile int tmp_v = abs(cur_vit_mask - bin); @@ -455,6 +423,71 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } +/* + * ar5008_hw_spur_mitigate - convert baseband spur frequency for external radios + * + * For non single-chip solutions. Converts to baseband spur frequency given the + * input channel frequency and compute register settings below. + */ +static void ar5008_hw_spur_mitigate(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + int bb_spur = AR_NO_SPUR; + int bin; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int tmp, new; + int i; + + int cur_bb_spur; + bool is2GHz = IS_CHAN_2GHZ(chan); + + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - (chan->channel * 10); + if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { + bb_spur = cur_bb_spur; + break; + } + } + + if (AR_NO_SPUR == bb_spur) + return; + + bin = bb_spur * 32; + + tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); + new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); + + new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + REG_WRITE(ah, AR_PHY_SPUR_REG, new); + + spur_delta_phase = ((bb_spur * 524288) / 100) & + AR_PHY_TIMING11_SPUR_DELTA_PHASE; + + denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; + spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; + + new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + REG_WRITE(ah, AR_PHY_TIMING11, new); + + ar5008_hw_cmn_spur_mitigate(ah, chan, bin); +} + /** * ar5008_hw_rf_alloc_ext_banks - allocates banks for external radio programming * @ah: atheros hardware structure @@ -507,7 +540,7 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah, return true; /* Setup rf parameters */ - eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); + eepMinorRev = ah->eep_ops->get_eeprom_rev(ah); for (i = 0; i < ah->iniBank6.ia_rows; i++) ah->analogBank6Data[i] = INI_RA(&ah->iniBank6, i, modesIndex); @@ -566,12 +599,14 @@ static void ar5008_hw_init_chain_masks(struct ath_hw *ah) case 0x5: REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); + fallthrough; case 0x3: if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) { REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7); REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7); break; } + fallthrough; case 0x1: case 0x2: case 0x7: @@ -610,7 +645,15 @@ static void ar5008_hw_override_ini(struct ath_hw *ah, REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); if (AR_SREV_9280_20_OR_LATER(ah)) { - val = REG_READ(ah, AR_PCU_MISC_MODE2); + /* + * For AR9280 and above, there is a new feature that allows + * Multicast search based on both MAC Address and Key ID. + * By default, this feature is enabled. But since the driver + * is not using this feature, we switch it off; otherwise + * multicast search based on MAC addr only will fail. + */ + val = REG_READ(ah, AR_PCU_MISC_MODE2) & + (~AR_ADHOC_MCAST_KEYID_ENABLE); if (!AR_SREV_9271(ah)) val &= ~AR_PCU_MISC_MODE2_HWWAR1; @@ -618,12 +661,11 @@ static void ar5008_hw_override_ini(struct ath_hw *ah, if (AR_SREV_9287_11_OR_LATER(ah)) val = val & (~AR_PCU_MISC_MODE2_HWWAR2); + val |= AR_PCU_MISC_MODE2_CFP_IGNORE; + REG_WRITE(ah, AR_PCU_MISC_MODE2, val); } - REG_SET_BIT(ah, AR_PHY_CCK_DETECT, - AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); - if (AR_SREV_9280_20_OR_LATER(ah)) return; /* @@ -659,16 +701,16 @@ static void ar5008_hw_set_channel_regs(struct ath_hw *ah, if (IS_CHAN_HT40(chan)) { phymode |= AR_PHY_FC_DYN2040_EN; - if ((chan->chanmode == CHANNEL_A_HT40PLUS) || - (chan->chanmode == CHANNEL_G_HT40PLUS)) + if (IS_CHAN_HT40PLUS(chan)) phymode |= AR_PHY_FC_DYN2040_PRI_CH; } + ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_PHY_TURBO, phymode); - ath9k_hw_set11nmac2040(ah); - - ENABLE_REGWRITE_BUFFER(ah); + /* This function do only REG_WRITE, so + * we can include it to REGWRITE_BUFFER. */ + ath9k_hw_set11nmac2040(ah, chan); REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); @@ -684,31 +726,12 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, int i, regWrites = 0; u32 modesIndex, freqIndex; - switch (chan->chanmode) { - case CHANNEL_A: - case CHANNEL_A_HT20: - modesIndex = 1; + if (IS_CHAN_5GHZ(chan)) { freqIndex = 1; - break; - case CHANNEL_A_HT40PLUS: - case CHANNEL_A_HT40MINUS: - modesIndex = 2; - freqIndex = 1; - break; - case CHANNEL_G: - case CHANNEL_G_HT20: - case CHANNEL_B: - modesIndex = 4; - freqIndex = 2; - break; - case CHANNEL_G_HT40PLUS: - case CHANNEL_G_HT40MINUS: - modesIndex = 3; + modesIndex = IS_CHAN_HT40(chan) ? 2 : 1; + } else { freqIndex = 2; - break; - - default: - return -EINVAL; + modesIndex = IS_CHAN_HT40(chan) ? 3 : 4; } /* @@ -807,8 +830,10 @@ static void ar5008_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan) if (chan == NULL) return; - rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) - ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; + if (IS_CHAN_2GHZ(chan)) + rfMode |= AR_PHY_MODE_DYNAMIC; + else + rfMode |= AR_PHY_MODE_OFDM; if (!AR_SREV_9280_20_OR_LATER(ah)) rfMode |= (IS_CHAN_5GHZ(chan)) ? @@ -932,7 +957,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, struct ath_common *common = ath9k_hw_common(ah); struct ath9k_channel *chan = ah->curchan; struct ar5416AniState *aniState = &ah->ani; - s32 value, value2; + s32 value; switch (cmd & ah->ani_function) { case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ @@ -1019,42 +1044,11 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, case ATH9K_ANI_FIRSTEP_LEVEL:{ u32 level = param; - if (level >= ARRAY_SIZE(firstep_table)) { - ath_dbg(common, ANI, - "ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%u > %zu)\n", - level, ARRAY_SIZE(firstep_table)); - return false; - } - - /* - * make register setting relative to default - * from INI file & cap value - */ - value = firstep_table[level] - - firstep_table[ATH9K_ANI_FIRSTEP_LVL] + - aniState->iniDef.firstep; - if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN) - value = ATH9K_SIG_FIRSTEP_SETTING_MIN; - if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX) - value = ATH9K_SIG_FIRSTEP_SETTING_MAX; + value = level * 2; REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRSTEP, - value); - /* - * we need to set first step low register too - * make register setting relative to default - * from INI file & cap value - */ - value2 = firstep_table[level] - - firstep_table[ATH9K_ANI_FIRSTEP_LVL] + - aniState->iniDef.firstepLow; - if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN) - value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN; - if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX) - value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX; - + AR_PHY_FIND_SIG_FIRSTEP, value); REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, - AR_PHY_FIND_SIG_FIRSTEP_LOW, value2); + AR_PHY_FIND_SIG_FIRSTEP_LOW, value); if (level != aniState->firstepLevel) { ath_dbg(common, ANI, @@ -1071,7 +1065,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, aniState->firstepLevel, level, ATH9K_ANI_FIRSTEP_LVL, - value2, + value, aniState->iniDef.firstepLow); if (level > aniState->firstepLevel) ah->stats.ast_ani_stepup++; @@ -1084,41 +1078,12 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ u32 level = param; - if (level >= ARRAY_SIZE(cycpwrThr1_table)) { - ath_dbg(common, ANI, - "ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%u > %zu)\n", - level, ARRAY_SIZE(cycpwrThr1_table)); - return false; - } - /* - * make register setting relative to default - * from INI file & cap value - */ - value = cycpwrThr1_table[level] - - cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] + - aniState->iniDef.cycpwrThr1; - if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN) - value = ATH9K_SIG_SPUR_IMM_SETTING_MIN; - if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX) - value = ATH9K_SIG_SPUR_IMM_SETTING_MAX; + value = (level + 1) * 2; REG_RMW_FIELD(ah, AR_PHY_TIMING5, - AR_PHY_TIMING5_CYCPWR_THR1, - value); + AR_PHY_TIMING5_CYCPWR_THR1, value); - /* - * set AR_PHY_EXT_CCA for extension channel - * make register setting relative to default - * from INI file & cap value - */ - value2 = cycpwrThr1_table[level] - - cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] + - aniState->iniDef.cycpwrThr1Ext; - if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN) - value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN; - if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX) - value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX; REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, - AR_PHY_EXT_TIMING5_CYCPWR_THR1, value2); + AR_PHY_EXT_TIMING5_CYCPWR_THR1, value - 1); if (level != aniState->spurImmunityLevel) { ath_dbg(common, ANI, @@ -1135,7 +1100,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, aniState->spurImmunityLevel, level, ATH9K_ANI_SPUR_IMMUNE_LVL, - value2, + value, aniState->iniDef.cycpwrThr1Ext); if (level > aniState->spurImmunityLevel) ah->stats.ast_ani_spurup++; @@ -1152,8 +1117,6 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, */ WARN_ON(1); break; - case ATH9K_ANI_PRESENT: - break; default: ath_dbg(common, ANI, "invalid cmd %u\n", cmd); return false; @@ -1213,12 +1176,11 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah) iniDef = &aniState->iniDef; - ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n", + ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz\n", ah->hw_version.macVersion, ah->hw_version.macRev, ah->opmode, - chan->channel, - chan->channelFlags); + chan->channel); val = REG_READ(ah, AR_PHY_SFCORR); iniDef->m1Thresh = MS(val, AR_PHY_SFCORR_M1_THRESH); @@ -1268,7 +1230,7 @@ static void ar5008_hw_set_nf_limits(struct ath_hw *ah) static void ar5008_hw_set_radar_params(struct ath_hw *ah, struct ath_hw_radar_conf *conf) { - u32 radar_0 = 0, radar_1 = 0; + u32 radar_0 = 0, radar_1; if (!conf) { REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA); @@ -1282,6 +1244,9 @@ static void ar5008_hw_set_radar_params(struct ath_hw *ah, radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI); radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND); + radar_1 = REG_READ(ah, AR_PHY_RADAR_1); + radar_1 &= ~(AR_PHY_RADAR_1_MAXLEN | AR_PHY_RADAR_1_RELSTEP_THRESH | + AR_PHY_RADAR_1_RELPWR_THRESH); radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI; radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK; radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN); @@ -1303,13 +1268,78 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah) conf->fir_power = -33; conf->radar_rssi = 20; conf->pulse_height = 10; - conf->pulse_rssi = 24; + conf->pulse_rssi = 15; conf->pulse_inband = 15; conf->pulse_maxlen = 255; conf->pulse_inband_step = 12; conf->radar_inband = 8; } +static void ar5008_hw_init_txpower_cck(struct ath_hw *ah, int16_t *rate_array) +{ +#define CCK_DELTA(_ah, x) ((OLC_FOR_AR9280_20_LATER(_ah)) ? max((x) - 2, 0) : (x)) + ah->tx_power[0] = CCK_DELTA(ah, rate_array[rate1l]); + ah->tx_power[1] = CCK_DELTA(ah, min(rate_array[rate2l], + rate_array[rate2s])); + ah->tx_power[2] = CCK_DELTA(ah, min(rate_array[rate5_5l], + rate_array[rate5_5s])); + ah->tx_power[3] = CCK_DELTA(ah, min(rate_array[rate11l], + rate_array[rate11s])); +#undef CCK_DELTA +} + +static void ar5008_hw_init_txpower_ofdm(struct ath_hw *ah, int16_t *rate_array, + int offset) +{ + int i, idx = 0; + + for (i = offset; i < offset + AR5008_OFDM_RATES; i++) { + ah->tx_power[i] = rate_array[idx]; + idx++; + } +} + +static void ar5008_hw_init_txpower_ht(struct ath_hw *ah, int16_t *rate_array, + int ss_offset, int ds_offset, + bool is_40, int ht40_delta) +{ + int i, mcs_idx = (is_40) ? AR5008_HT40_SHIFT : AR5008_HT20_SHIFT; + + for (i = ss_offset; i < ss_offset + AR5008_HT_SS_RATES; i++) { + ah->tx_power[i] = rate_array[mcs_idx] + ht40_delta; + mcs_idx++; + } + memcpy(&ah->tx_power[ds_offset], &ah->tx_power[ss_offset], + AR5008_HT_SS_RATES); +} + +void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array, + struct ath9k_channel *chan, int ht40_delta) +{ + if (IS_CHAN_5GHZ(chan)) { + ar5008_hw_init_txpower_ofdm(ah, rate_array, + AR5008_11NA_OFDM_SHIFT); + if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) { + ar5008_hw_init_txpower_ht(ah, rate_array, + AR5008_11NA_HT_SS_SHIFT, + AR5008_11NA_HT_DS_SHIFT, + IS_CHAN_HT40(chan), + ht40_delta); + } + } else { + ar5008_hw_init_txpower_cck(ah, rate_array); + ar5008_hw_init_txpower_ofdm(ah, rate_array, + AR5008_11NG_OFDM_SHIFT); + if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) { + ar5008_hw_init_txpower_ht(ah, rate_array, + AR5008_11NG_HT_SS_SHIFT, + AR5008_11NG_HT_DS_SHIFT, + IS_CHAN_HT40(chan), + ht40_delta); + } + } +} + int ar5008_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); diff --git a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h index 59524e1d4678..aa5f086fa3b0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h @@ -459,43 +459,6 @@ static const u32 ar5416Common_9100[][2] = { {0x0000a3e0, 0x000001ce}, }; -static const u32 ar5416Bank6_9100[][3] = { - /* Addr 5G 2G */ - {0x0000989c, 0x00000000, 0x00000000}, - {0x0000989c, 0x00000000, 0x00000000}, - {0x0000989c, 0x00000000, 0x00000000}, - {0x0000989c, 0x00e00000, 0x00e00000}, - {0x0000989c, 0x005e0000, 0x005e0000}, - {0x0000989c, 0x00120000, 0x00120000}, - {0x0000989c, 0x00620000, 0x00620000}, - {0x0000989c, 0x00020000, 0x00020000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x005f0000, 0x005f0000}, - {0x0000989c, 0x00870000, 0x00870000}, - {0x0000989c, 0x00f90000, 0x00f90000}, - {0x0000989c, 0x007b0000, 0x007b0000}, - {0x0000989c, 0x00ff0000, 0x00ff0000}, - {0x0000989c, 0x00f50000, 0x00f50000}, - {0x0000989c, 0x00dc0000, 0x00dc0000}, - {0x0000989c, 0x00110000, 0x00110000}, - {0x0000989c, 0x006100a8, 0x006100a8}, - {0x0000989c, 0x004210a2, 0x004210a2}, - {0x0000989c, 0x0014000f, 0x0014000f}, - {0x0000989c, 0x00c40002, 0x00c40002}, - {0x0000989c, 0x003000f2, 0x003000f2}, - {0x0000989c, 0x00440016, 0x00440016}, - {0x0000989c, 0x00410040, 0x00410040}, - {0x0000989c, 0x000180d6, 0x000180d6}, - {0x0000989c, 0x0000c0aa, 0x0000c0aa}, - {0x0000989c, 0x000000b1, 0x000000b1}, - {0x0000989c, 0x00002000, 0x00002000}, - {0x0000989c, 0x000000d4, 0x000000d4}, - {0x000098d0, 0x0000000f, 0x0010000f}, -}; - static const u32 ar5416Bank6TPC_9100[][3] = { /* Addr 5G 2G */ {0x0000989c, 0x00000000, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 9f589744a9f9..c8b3f3aaa45b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -19,6 +19,8 @@ #include "ar9002_phy.h" #define AR9285_CLCAL_REDO_THRESH 1 +/* AGC & I/Q calibrations time limit, ms */ +#define AR9002_CAL_MAX_TIME 30000 enum ar9002_cal_types { ADC_GAIN_CAL = BIT(0), @@ -33,16 +35,12 @@ static bool ar9002_hw_is_cal_supported(struct ath_hw *ah, bool supported = false; switch (ah->supp_cals & cal_type) { case IQ_MISMATCH_CAL: - /* Run IQ Mismatch for non-CCK only */ - if (!IS_CHAN_B(chan)) - supported = true; + supported = true; break; case ADC_GAIN_CAL: case ADC_DC_CAL: - /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */ - if (!IS_CHAN_B(chan) && - !((IS_CHAN_2GHZ(chan) || IS_CHAN_A_FAST_CLOCK(ah, chan)) && - IS_CHAN_HT20(chan))) + /* Run even/odd ADCs calibrations for HT40 channels only */ + if (IS_CHAN_HT40(chan)) supported = true; break; } @@ -108,6 +106,14 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah, } else { ar9002_hw_setup_calibration(ah, currCal); } + } else if (time_after(jiffies, ah->cal_start_time + + msecs_to_jiffies(AR9002_CAL_MAX_TIME))) { + REG_CLR_BIT(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_DO_CAL); + ath_dbg(ath9k_hw_common(ah), CALIBRATE, + "calibration timeout\n"); + currCal->calState = CAL_WAITING; /* Try later */ + iscaldone = true; } } else if (!(caldata->CalValid & currCal->calData->calType)) { ath9k_hw_reset_calibration(ah, currCal); @@ -433,46 +439,43 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) u32 regVal; unsigned int i; u32 regList[][2] = { - { 0x786c, 0 }, - { 0x7854, 0 }, - { 0x7820, 0 }, - { 0x7824, 0 }, - { 0x7868, 0 }, - { 0x783c, 0 }, - { 0x7838, 0 } , - { 0x7828, 0 } , + { AR9285_AN_TOP3, 0 }, + { AR9285_AN_RXTXBB1, 0 }, + { AR9285_AN_RF2G1, 0 }, + { AR9285_AN_RF2G2, 0 }, + { AR9285_AN_TOP2, 0 }, + { AR9285_AN_RF2G8, 0 }, + { AR9285_AN_RF2G7, 0 }, + { AR9285_AN_RF2G3, 0 }, }; - for (i = 0; i < ARRAY_SIZE(regList); i++) - regList[i][1] = REG_READ(ah, regList[i][0]); - - regVal = REG_READ(ah, 0x7834); - regVal &= (~(0x1)); - REG_WRITE(ah, 0x7834, regVal); - regVal = REG_READ(ah, 0x9808); - regVal |= (0x1 << 27); - REG_WRITE(ah, 0x9808, regVal); + REG_READ_ARRAY(ah, regList, ARRAY_SIZE(regList)); + ENABLE_REG_RMW_BUFFER(ah); + /* 7834, b1=0 */ + REG_CLR_BIT(ah, AR9285_AN_RF2G6, 1 << 0); + /* 9808, b27=1 */ + REG_SET_BIT(ah, 0x9808, 1 << 27); /* 786c,b23,1, pwddac=1 */ - REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); + REG_SET_BIT(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC); /* 7854, b5,1, pdrxtxbb=1 */ - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); + REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1); /* 7854, b7,1, pdv2i=1 */ - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); + REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I); /* 7854, b8,1, pddacinterface=1 */ - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); + REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF); /* 7824,b12,0, offcal=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); + REG_CLR_BIT(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL); /* 7838, b1,0, pwddb=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); + REG_CLR_BIT(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB); /* 7820,b11,0, enpacal=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); + REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL); /* 7820,b25,1, pdpadrv1=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); + REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1); /* 7820,b24,0, pdpadrv2=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); + REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2); /* 7820,b23,0, pdpaout=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); + REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT); /* 783c,b14-16,7, padrvgn2tab_0=7 */ REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); /* @@ -480,8 +483,9 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) * does not matter since we turn it off */ REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); - + /* 7828, b0-11, ccom=fff */ REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff); + REG_RMW_BUFFER_FLUSH(ah); /* Set: * localmode=1,bmode=1,bmoderxtx=1,synthon=1, @@ -493,15 +497,16 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) /* find off_6_1; */ for (i = 6; i > 0; i--) { - regVal = REG_READ(ah, 0x7834); + regVal = REG_READ(ah, AR9285_AN_RF2G6); regVal |= (1 << (20 + i)); - REG_WRITE(ah, 0x7834, regVal); + REG_WRITE(ah, AR9285_AN_RF2G6, regVal); udelay(1); /* regVal = REG_READ(ah, 0x7834); */ regVal &= (~(0x1 << (20 + i))); - regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9) + regVal |= (MS(REG_READ(ah, AR9285_AN_RF2G9), + AR9285_AN_RXTXBB1_SPARE9) << (20 + i)); - REG_WRITE(ah, 0x7834, regVal); + REG_WRITE(ah, AR9285_AN_RF2G6, regVal); } regVal = (regVal >> 20) & 0x7f; @@ -518,15 +523,15 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) ah->pacal_info.prev_offset = regVal; } - ENABLE_REGWRITE_BUFFER(ah); - regVal = REG_READ(ah, 0x7834); - regVal |= 0x1; - REG_WRITE(ah, 0x7834, regVal); - regVal = REG_READ(ah, 0x9808); - regVal &= (~(0x1 << 27)); - REG_WRITE(ah, 0x9808, regVal); + ENABLE_REG_RMW_BUFFER(ah); + /* 7834, b1=1 */ + REG_SET_BIT(ah, AR9285_AN_RF2G6, 1 << 0); + /* 9808, b27=0 */ + REG_CLR_BIT(ah, 0x9808, 1 << 27); + REG_RMW_BUFFER_FLUSH(ah); + ENABLE_REGWRITE_BUFFER(ah); for (i = 0; i < ARRAY_SIZE(regList); i++) REG_WRITE(ah, regList[i][0], regList[i][1]); @@ -654,40 +659,58 @@ static void ar9002_hw_pa_cal(struct ath_hw *ah, bool is_reset) static void ar9002_hw_olc_temp_compensation(struct ath_hw *ah) { - if (OLC_FOR_AR9287_10_LATER) + if (OLC_FOR_AR9287_10_LATER(ah)) ar9287_hw_olc_temp_compensation(ah); - else if (OLC_FOR_AR9280_20_LATER) + else if (OLC_FOR_AR9280_20_LATER(ah)) ar9280_hw_olc_temp_compensation(ah); } -static bool ar9002_hw_calibrate(struct ath_hw *ah, - struct ath9k_channel *chan, - u8 rxchainmask, - bool longcal) +static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal) { - bool iscaldone = true; struct ath9k_cal_list *currCal = ah->cal_list_curr; - bool nfcal, nfcal_pending = false; + bool nfcal, nfcal_pending = false, percal_pending; + int ret; + + nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) & AR_PHY_AGC_CONTROL_NF); + if (ah->caldata) { + nfcal_pending = test_bit(NFCAL_PENDING, &ah->caldata->cal_flags); + if (longcal) /* Remember to not miss */ + set_bit(LONGCAL_PENDING, &ah->caldata->cal_flags); + else if (test_bit(LONGCAL_PENDING, &ah->caldata->cal_flags)) + longcal = true; /* Respin a previous one */ + } - nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF); - if (ah->caldata) - nfcal_pending = ah->caldata->nfcal_pending; - - if (currCal && !nfcal && - (currCal->calState == CAL_RUNNING || - currCal->calState == CAL_WAITING)) { - iscaldone = ar9002_hw_per_calibration(ah, chan, - rxchainmask, currCal); - if (iscaldone) { - ah->cal_list_curr = currCal = currCal->calNext; - - if (currCal->calState == CAL_WAITING) { - iscaldone = false; - ath9k_hw_reset_calibration(ah, currCal); - } + percal_pending = (currCal && + (currCal->calState == CAL_RUNNING || + currCal->calState == CAL_WAITING)); + + if (percal_pending && !nfcal) { + if (!ar9002_hw_per_calibration(ah, chan, rxchainmask, currCal)) + return 0; + + /* Looking for next waiting calibration if any */ + for (currCal = currCal->calNext; currCal != ah->cal_list_curr; + currCal = currCal->calNext) { + if (currCal->calState == CAL_WAITING) + break; + } + if (currCal->calState == CAL_WAITING) { + percal_pending = true; + ah->cal_list_curr = currCal; + } else { + percal_pending = false; + ah->cal_list_curr = ah->cal_list; } } + /* Do not start a next calibration if the longcal is in action */ + if (percal_pending && !nfcal && !longcal) { + ath9k_hw_reset_calibration(ah, currCal); + + return 0; + } + /* Do NF cal only at longer intervals */ if (longcal || nfcal_pending) { /* @@ -701,10 +724,15 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah, * NF is slow time-variant, so it is OK to use a * historical value. */ - ath9k_hw_loadnf(ah, ah->curchan); + ret = ath9k_hw_loadnf(ah, ah->curchan); + if (ret < 0) + return ret; } if (longcal) { + if (ah->caldata) + clear_bit(LONGCAL_PENDING, + &ah->caldata->cal_flags); ath9k_hw_start_nfcal(ah, false); /* Do periodic PAOffset Cal */ ar9002_hw_pa_cal(ah, false); @@ -712,7 +740,7 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah, } } - return iscaldone; + return !percal_pending; } /* Carrier leakage Calibration fix */ @@ -724,11 +752,11 @@ static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan) if (IS_CHAN_HT20(chan)) { REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_FLTR_CAL); REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_CAL); + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { ath_dbg(common, CALIBRATE, "offset calibration failed to complete in %d ms; noisy environment?\n", @@ -740,10 +768,10 @@ static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan) REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); } REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_FLTR_CAL); REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_CAL); + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { ath_dbg(common, CALIBRATE, "offset calibration failed to complete in %d ms; noisy environment?\n", @@ -753,7 +781,7 @@ static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan) REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_FLTR_CAL); return true; } @@ -829,17 +857,17 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) if (!AR_SREV_9287_11_OR_LATER(ah)) REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_FLTR_CAL); } /* Calibrate the AGC */ - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | + REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah), + REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) | AR_PHY_AGC_CONTROL_CAL); /* Poll for offset calibration complete */ - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { ath_dbg(common, CALIBRATE, @@ -852,16 +880,15 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) if (!AR_SREV_9287_11_OR_LATER(ah)) REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_FLTR_CAL); } } /* Do PA Calibration */ ar9002_hw_pa_cal(ah, true); - - if (ah->caldata) - ah->caldata->nfcal_pending = true; + ath9k_hw_loadnf(ah, chan); + ath9k_hw_start_nfcal(ah, true); ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index 8dc2d089cdef..b26224480041 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -32,12 +32,8 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah) return 0; } - if (ah->config.pcie_clock_req) - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9280PciePhy_clkreq_off_L1_9280); - else - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9280PciePhy_clkreq_always_on_L1_9280); + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9280PciePhy_clkreq_always_on_L1_9280); if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1); @@ -112,8 +108,7 @@ static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah) { u32 rxgain_type; - if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= - AR5416_EEP_MINOR_VER_17) { + if (ah->eep_ops->get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_17) { rxgain_type = ah->eep_ops->get_eeprom(ah, EEP_RXGAIN_TYPE); if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF) @@ -133,8 +128,7 @@ static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah) static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type) { - if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= - AR5416_EEP_MINOR_VER_19) { + if (ah->eep_ops->get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_19) { if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9280Modes_high_power_tx_gain_9280_2); @@ -255,9 +249,9 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah, if (power_off) { /* clear bit 19 to disable L1 */ - REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); + REG_CLR_BIT(ah, AR_PCIE_PM_CTRL(ah), AR_PCIE_PM_CTRL_ENA); - val = REG_READ(ah, AR_WA); + val = REG_READ(ah, AR_WA(ah)); /* * Set PCIe workaround bits @@ -269,13 +263,12 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah, if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE) val |= AR_WA_D3_L1_DISABLE; } else { - if (((AR_SREV_9285(ah) || - AR_SREV_9271(ah) || - AR_SREV_9287(ah)) && - (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) || - (AR_SREV_9280(ah) && - (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) { - val |= AR_WA_D3_L1_DISABLE; + if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah)) { + if (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE) + val |= AR_WA_D3_L1_DISABLE; + } else if (AR_SREV_9280(ah)) { + if (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE) + val |= AR_WA_D3_L1_DISABLE; } } @@ -293,28 +286,22 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah, if (AR_SREV_9285E_20(ah)) val |= AR_WA_BIT23; - REG_WRITE(ah, AR_WA, val); + REG_WRITE(ah, AR_WA(ah), val); } else { if (ah->config.pcie_waen) { val = ah->config.pcie_waen; - if (!power_off) - val &= (~AR_WA_D3_L1_DISABLE); + val &= (~AR_WA_D3_L1_DISABLE); } else { - if (AR_SREV_9285(ah) || - AR_SREV_9271(ah) || - AR_SREV_9287(ah)) { + if (AR_SREV_9285(ah) || AR_SREV_9271(ah) || AR_SREV_9287(ah)) { val = AR9285_WA_DEFAULT; - if (!power_off) - val &= (~AR_WA_D3_L1_DISABLE); - } - else if (AR_SREV_9280(ah)) { + val &= (~AR_WA_D3_L1_DISABLE); + } else if (AR_SREV_9280(ah)) { /* * For AR9280 chips, bit 22 of 0x4004 * needs to be set. */ val = AR9280_WA_DEFAULT; - if (!power_off) - val &= (~AR_WA_D3_L1_DISABLE); + val &= (~AR_WA_D3_L1_DISABLE); } else { val = AR_WA_DEFAULT; } @@ -327,10 +314,10 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah, if (AR_SREV_9285E_20(ah)) val |= AR_WA_BIT23; - REG_WRITE(ah, AR_WA, val); + REG_WRITE(ah, AR_WA(ah), val); /* set bit 19 to allow forcing of pcie core into L1 state */ - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); + REG_SET_BIT(ah, AR_PCIE_PM_CTRL(ah), AR_PCIE_PM_CTRL_ENA); } } @@ -394,7 +381,21 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah) } } -/* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */ +static void ar9002_hw_init_hang_checks(struct ath_hw *ah) +{ + if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) { + ah->config.hw_hang_checks |= HW_BB_RIFS_HANG; + ah->config.hw_hang_checks |= HW_BB_DFS_HANG; + } + + if (AR_SREV_9280(ah)) + ah->config.hw_hang_checks |= HW_BB_RX_CLEAR_STUCK_HANG; + + if (AR_SREV_5416(ah) || AR_SREV_9100(ah) || AR_SREV_9160(ah)) + ah->config.hw_hang_checks |= HW_MAC_HANG; +} + +/* Sets up the AR5008/AR9001/AR9002 hardware family callbacks */ int ar9002_hw_attach_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); @@ -406,6 +407,7 @@ int ar9002_hw_attach_ops(struct ath_hw *ah) return ret; priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs; + priv_ops->init_hang_checks = ar9002_hw_init_hang_checks; ops->config_pci_powersave = ar9002_hw_configpcipowersave; @@ -426,28 +428,10 @@ void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan) u32 modesIndex; int i; - switch (chan->chanmode) { - case CHANNEL_A: - case CHANNEL_A_HT20: - modesIndex = 1; - break; - case CHANNEL_A_HT40PLUS: - case CHANNEL_A_HT40MINUS: - modesIndex = 2; - break; - case CHANNEL_G: - case CHANNEL_G_HT20: - case CHANNEL_B: - modesIndex = 4; - break; - case CHANNEL_G_HT40PLUS: - case CHANNEL_G_HT40MINUS: - modesIndex = 3; - break; - - default: - return; - } + if (IS_CHAN_5GHZ(chan)) + modesIndex = IS_CHAN_HT40(chan) ? 2 : 1; + else + modesIndex = IS_CHAN_HT40(chan) ? 3 : 4; ENABLE_REGWRITE_BUFFER(ah); diff --git a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h index 4d18c66a6790..e01b5c3728b8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h @@ -897,20 +897,6 @@ static const u32 ar9280Modes_original_tx_gain_9280_2[][5] = { {0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480}, }; -static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = { - /* Addr allmodes */ - {0x00004040, 0x9248fd00}, - {0x00004040, 0x24924924}, - {0x00004040, 0xa8000019}, - {0x00004040, 0x13160820}, - {0x00004040, 0xe5980560}, - {0x00004040, 0xc01dcffc}, - {0x00004040, 0x1aaabe41}, - {0x00004040, 0xbe105554}, - {0x00004040, 0x00043007}, - {0x00004044, 0x00000000}, -}; - static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { /* Addr allmodes */ {0x00004040, 0x9248fd00}, diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 8d78253c26ce..b70cd4af1ae0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -21,7 +21,7 @@ static void ar9002_hw_rx_enable(struct ath_hw *ah) { - REG_WRITE(ah, AR_CR, AR_CR_RXE); + REG_WRITE(ah, AR_CR, AR_CR_RXE(ah)); } static void ar9002_hw_set_desc_link(void *ds, u32 ds_link) @@ -29,7 +29,8 @@ static void ar9002_hw_set_desc_link(void *ds, u32 ds_link) ((struct ath_desc*) ds)->ds_link = ds_link; } -static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) +static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked, + u32 *sync_cause_p) { u32 isr = 0; u32 mask2 = 0; @@ -39,14 +40,14 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) struct ath_common *common = ath9k_hw_common(ah); if (!AR_SREV_9100(ah)) { - if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { - if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) + if (REG_READ(ah, AR_INTR_ASYNC_CAUSE(ah)) & AR_INTR_MAC_IRQ) { + if ((REG_READ(ah, AR_RTC_STATUS(ah)) & AR_RTC_STATUS_M(ah)) == AR_RTC_STATUS_ON) { isr = REG_READ(ah, AR_ISR); } } - sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & + sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE(ah)) & AR_INTR_SYNC_DEFAULT; *masked = 0; @@ -76,9 +77,16 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) mask2 |= ATH9K_INT_CST; if (isr2 & AR_ISR_S2_TSFOOR) mask2 |= ATH9K_INT_TSFOOR; + + if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { + REG_WRITE(ah, AR_ISR_S2, isr2); + isr &= ~AR_ISR_BCNMISC; + } } - isr = REG_READ(ah, AR_ISR_RAC); + if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) + isr = REG_READ(ah, AR_ISR_RAC); + if (isr == 0xffffffff) { *masked = 0; return false; @@ -97,11 +105,23 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) *masked |= ATH9K_INT_TX; - s0_s = REG_READ(ah, AR_ISR_S0_S); - ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK); - ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC); + if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) { + s0_s = REG_READ(ah, AR_ISR_S0_S); + s1_s = REG_READ(ah, AR_ISR_S1_S); + } else { + s0_s = REG_READ(ah, AR_ISR_S0); + REG_WRITE(ah, AR_ISR_S0, s0_s); + s1_s = REG_READ(ah, AR_ISR_S1); + REG_WRITE(ah, AR_ISR_S1, s1_s); + + isr &= ~(AR_ISR_TXOK | + AR_ISR_TXDESC | + AR_ISR_TXERR | + AR_ISR_TXEOL); + } - s1_s = REG_READ(ah, AR_ISR_S1_S); + ah->intr_txqs = MS(s0_s, AR_ISR_S0_QCU_TXOK); + ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC); ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR); ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL); } @@ -114,13 +134,15 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) *masked |= mask2; } - if (AR_SREV_9100(ah)) - return true; - - if (isr & AR_ISR_GENTMR) { + if (!AR_SREV_9100(ah) && (isr & AR_ISR_GENTMR)) { u32 s5_s; - s5_s = REG_READ(ah, AR_ISR_S5_S); + if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) { + s5_s = REG_READ(ah, AR_ISR_S5_S(ah)); + } else { + s5_s = REG_READ(ah, AR_ISR_S5); + } + ah->intr_gen_timer_trigger = MS(s5_s, AR_ISR_S5_GENTIMER_TRIG); @@ -133,10 +155,24 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) if ((s5_s & AR_ISR_S5_TIM_TIMER) && !(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) *masked |= ATH9K_INT_TIM_TIMER; + + if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { + REG_WRITE(ah, AR_ISR_S5, s5_s); + isr &= ~AR_ISR_GENTMR; + } } + if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { + REG_WRITE(ah, AR_ISR, isr); + REG_READ(ah, AR_ISR); + } + + if (AR_SREV_9100(ah)) + return true; + if (sync_cause) { - ath9k_debug_sync_cause(common, sync_cause); + if (sync_cause_p) + *sync_cause_p = sync_cause; fatal_int = (sync_cause & (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) @@ -165,8 +201,8 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); } - REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); - (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); + REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR(ah), sync_cause); + (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR(ah)); } return true; @@ -184,8 +220,8 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) ads->ds_txstatus6 = ads->ds_txstatus7 = 0; ads->ds_txstatus8 = ads->ds_txstatus9 = 0; - ACCESS_ONCE(ads->ds_link) = i->link; - ACCESS_ONCE(ads->ds_data) = i->buf_addr[0]; + WRITE_ONCE(ads->ds_link, i->link); + WRITE_ONCE(ads->ds_data, i->buf_addr[0]); ctl1 = i->buf_len[0] | (i->is_last ? 0 : AR_TxMore); ctl6 = SM(i->keytype, AR_EncrType); @@ -199,26 +235,26 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) if ((i->is_first || i->is_last) && i->aggr != AGGR_BUF_MIDDLE && i->aggr != AGGR_BUF_LAST) { - ACCESS_ONCE(ads->ds_ctl2) = set11nTries(i->rates, 0) + WRITE_ONCE(ads->ds_ctl2, set11nTries(i->rates, 0) | set11nTries(i->rates, 1) | set11nTries(i->rates, 2) | set11nTries(i->rates, 3) | (i->dur_update ? AR_DurUpdateEna : 0) - | SM(0, AR_BurstDur); + | SM(0, AR_BurstDur)); - ACCESS_ONCE(ads->ds_ctl3) = set11nRate(i->rates, 0) + WRITE_ONCE(ads->ds_ctl3, set11nRate(i->rates, 0) | set11nRate(i->rates, 1) | set11nRate(i->rates, 2) - | set11nRate(i->rates, 3); + | set11nRate(i->rates, 3)); } else { - ACCESS_ONCE(ads->ds_ctl2) = 0; - ACCESS_ONCE(ads->ds_ctl3) = 0; + WRITE_ONCE(ads->ds_ctl2, 0); + WRITE_ONCE(ads->ds_ctl3, 0); } if (!i->is_first) { - ACCESS_ONCE(ads->ds_ctl0) = 0; - ACCESS_ONCE(ads->ds_ctl1) = ctl1; - ACCESS_ONCE(ads->ds_ctl6) = ctl6; + WRITE_ONCE(ads->ds_ctl0, 0); + WRITE_ONCE(ads->ds_ctl1, ctl1); + WRITE_ONCE(ads->ds_ctl6, ctl6); return; } @@ -231,7 +267,7 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) switch (i->aggr) { case AGGR_BUF_FIRST: ctl6 |= SM(i->aggr_len, AR_AggrLen); - /* fall through */ + fallthrough; case AGGR_BUF_MIDDLE: ctl1 |= AR_IsAggr | AR_MoreAggr; ctl6 |= SM(i->ndelim, AR_PadDelim); @@ -243,33 +279,38 @@ ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) break; } - ACCESS_ONCE(ads->ds_ctl0) = (i->pkt_len & AR_FrameLen) + WRITE_ONCE(ads->ds_ctl0, (i->pkt_len & AR_FrameLen) | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) - | SM(i->txpower, AR_XmitPower) + | SM(i->txpower[0], AR_XmitPower0) | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | (i->flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) | (i->flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) | (i->flags & ATH9K_TXDESC_RTSENA ? AR_RTSEnable : - (i->flags & ATH9K_TXDESC_CTSENA ? AR_CTSEnable : 0)); + (i->flags & ATH9K_TXDESC_CTSENA ? AR_CTSEnable : 0))); - ACCESS_ONCE(ads->ds_ctl1) = ctl1; - ACCESS_ONCE(ads->ds_ctl6) = ctl6; + WRITE_ONCE(ads->ds_ctl1, ctl1); + WRITE_ONCE(ads->ds_ctl6, ctl6); if (i->aggr == AGGR_BUF_MIDDLE || i->aggr == AGGR_BUF_LAST) return; - ACCESS_ONCE(ads->ds_ctl4) = set11nPktDurRTSCTS(i->rates, 0) - | set11nPktDurRTSCTS(i->rates, 1); + WRITE_ONCE(ads->ds_ctl4, set11nPktDurRTSCTS(i->rates, 0) + | set11nPktDurRTSCTS(i->rates, 1)); + + WRITE_ONCE(ads->ds_ctl5, set11nPktDurRTSCTS(i->rates, 2) + | set11nPktDurRTSCTS(i->rates, 3)); - ACCESS_ONCE(ads->ds_ctl5) = set11nPktDurRTSCTS(i->rates, 2) - | set11nPktDurRTSCTS(i->rates, 3); + WRITE_ONCE(ads->ds_ctl7, + set11nRateFlags(i->rates, 0) | set11nChainSel(i->rates, 0) + | set11nRateFlags(i->rates, 1) | set11nChainSel(i->rates, 1) + | set11nRateFlags(i->rates, 2) | set11nChainSel(i->rates, 2) + | set11nRateFlags(i->rates, 3) | set11nChainSel(i->rates, 3) + | SM(i->rtscts_rate, AR_RTSCTSRate)); - ACCESS_ONCE(ads->ds_ctl7) = set11nRateFlags(i->rates, 0) - | set11nRateFlags(i->rates, 1) - | set11nRateFlags(i->rates, 2) - | set11nRateFlags(i->rates, 3) - | SM(i->rtscts_rate, AR_RTSCTSRate); + WRITE_ONCE(ads->ds_ctl9, SM(i->txpower[1], AR_XmitPower1)); + WRITE_ONCE(ads->ds_ctl10, SM(i->txpower[2], AR_XmitPower2)); + WRITE_ONCE(ads->ds_ctl11, SM(i->txpower[3], AR_XmitPower3)); } static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, @@ -278,7 +319,7 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, struct ar5416_desc *ads = AR5416DESC(ds); u32 status; - status = ACCESS_ONCE(ads->ds_txstatus9); + status = READ_ONCE(ads->ds_txstatus9); if ((status & AR_TxDone) == 0) return -EINPROGRESS; @@ -292,7 +333,7 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->ts_rateindex = MS(status, AR_FinalTxIdx); ts->ts_seqnum = MS(status, AR_SeqNum); - status = ACCESS_ONCE(ads->ds_txstatus0); + status = READ_ONCE(ads->ds_txstatus0); ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00); ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01); ts->ts_rssi_ctl2 = MS(status, AR_TxRSSIAnt02); @@ -302,7 +343,7 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->ba_high = ads->AR_BaBitmapHigh; } - status = ACCESS_ONCE(ads->ds_txstatus1); + status = READ_ONCE(ads->ds_txstatus1); if (status & AR_FrmXmitOK) ts->ts_status |= ATH9K_TX_ACKED; else { @@ -331,7 +372,7 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->ts_longretry = MS(status, AR_DataFailCnt); ts->ts_virtcol = MS(status, AR_VirtRetryCnt); - status = ACCESS_ONCE(ads->ds_txstatus5); + status = READ_ONCE(ads->ds_txstatus5); ts->ts_rssi = MS(status, AR_TxRSSICombined); ts->ts_rssi_ext0 = MS(status, AR_TxRSSIAnt10); ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11); @@ -344,6 +385,24 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, return 0; } +static int ar9002_hw_get_duration(struct ath_hw *ah, const void *ds, int index) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + switch (index) { + case 0: + return MS(READ_ONCE(ads->ds_ctl4), AR_PacketDur0); + case 1: + return MS(READ_ONCE(ads->ds_ctl4), AR_PacketDur1); + case 2: + return MS(READ_ONCE(ads->ds_ctl5), AR_PacketDur2); + case 3: + return MS(READ_ONCE(ads->ds_ctl5), AR_PacketDur3); + default: + return -1; + } +} + void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags) { @@ -366,4 +425,5 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah) ops->get_isr = ar9002_hw_get_isr; ops->set_txdesc = ar9002_set_txdesc; ops->proc_txdesc = ar9002_hw_proc_txdesc; + ops->get_duration = ar9002_hw_get_duration; } diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index f4003512d8d5..23ac6b7c2cbd 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -119,6 +119,7 @@ static int ar9002_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) aModeRefSel = 2; if (aModeRefSel) break; + fallthrough; case 1: default: aModeRefSel = 0; @@ -169,39 +170,21 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah, { int bb_spur = AR_NO_SPUR; int freq; - int bin, cur_bin; + int bin; int bb_spur_off, spur_subchannel_sd; int spur_freq_sd; int spur_delta_phase; int denominator; - int upper, lower, cur_vit_mask; int tmp, newVal; int i; - static const int pilot_mask_reg[4] = { - AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 - }; - static const int chan_mask_reg[4] = { - AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 - }; - static const int inc[4] = { 0, 100, 0, 0 }; struct chan_centers centers; - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; int cur_bb_spur; bool is2GHz = IS_CHAN_2GHZ(chan); - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - ath9k_hw_get_channel_centers(ah, chan, ¢ers); freq = centers.synth_center; - ah->config.spurmode = SPUR_ENABLE_EEPROM; for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); @@ -289,135 +272,7 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah, newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); - cur_bin = -6000; - upper = bin + 100; - lower = bin - 100; - - for (i = 0; i < 4; i++) { - int pilot_mask = 0; - int chan_mask = 0; - int bp = 0; - for (bp = 0; bp < 30; bp++) { - if ((cur_bin > lower) && (cur_bin < upper)) { - pilot_mask = pilot_mask | 0x1 << bp; - chan_mask = chan_mask | 0x1 << bp; - } - cur_bin += 100; - } - cur_bin += inc[i]; - REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); - REG_WRITE(ah, chan_mask_reg[i], chan_mask); - } - - cur_vit_mask = 6100; - upper = bin + 120; - lower = bin - 120; - - for (i = 0; i < 123; i++) { - if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - - /* workaround for gcc bug #37014 */ - volatile int tmp_v = abs(cur_vit_mask - bin); - - if (tmp_v < 75) - mask_amt = 1; - else - mask_amt = 0; - if (cur_vit_mask < 0) - mask_m[abs(cur_vit_mask / 100)] = mask_amt; - else - mask_p[cur_vit_mask / 100] = mask_amt; - } - cur_vit_mask -= 100; - } - - tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) - | (mask_m[48] << 26) | (mask_m[49] << 24) - | (mask_m[50] << 22) | (mask_m[51] << 20) - | (mask_m[52] << 18) | (mask_m[53] << 16) - | (mask_m[54] << 14) | (mask_m[55] << 12) - | (mask_m[56] << 10) | (mask_m[57] << 8) - | (mask_m[58] << 6) | (mask_m[59] << 4) - | (mask_m[60] << 2) | (mask_m[61] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); - REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - - tmp_mask = (mask_m[31] << 28) - | (mask_m[32] << 26) | (mask_m[33] << 24) - | (mask_m[34] << 22) | (mask_m[35] << 20) - | (mask_m[36] << 18) | (mask_m[37] << 16) - | (mask_m[48] << 14) | (mask_m[39] << 12) - | (mask_m[40] << 10) | (mask_m[41] << 8) - | (mask_m[42] << 6) | (mask_m[43] << 4) - | (mask_m[44] << 2) | (mask_m[45] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); - - tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) - | (mask_m[18] << 26) | (mask_m[18] << 24) - | (mask_m[20] << 22) | (mask_m[20] << 20) - | (mask_m[22] << 18) | (mask_m[22] << 16) - | (mask_m[24] << 14) | (mask_m[24] << 12) - | (mask_m[25] << 10) | (mask_m[26] << 8) - | (mask_m[27] << 6) | (mask_m[28] << 4) - | (mask_m[29] << 2) | (mask_m[30] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); - - tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) - | (mask_m[2] << 26) | (mask_m[3] << 24) - | (mask_m[4] << 22) | (mask_m[5] << 20) - | (mask_m[6] << 18) | (mask_m[7] << 16) - | (mask_m[8] << 14) | (mask_m[9] << 12) - | (mask_m[10] << 10) | (mask_m[11] << 8) - | (mask_m[12] << 6) | (mask_m[13] << 4) - | (mask_m[14] << 2) | (mask_m[15] << 0); - REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); - - tmp_mask = (mask_p[15] << 28) - | (mask_p[14] << 26) | (mask_p[13] << 24) - | (mask_p[12] << 22) | (mask_p[11] << 20) - | (mask_p[10] << 18) | (mask_p[9] << 16) - | (mask_p[8] << 14) | (mask_p[7] << 12) - | (mask_p[6] << 10) | (mask_p[5] << 8) - | (mask_p[4] << 6) | (mask_p[3] << 4) - | (mask_p[2] << 2) | (mask_p[1] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - - tmp_mask = (mask_p[30] << 28) - | (mask_p[29] << 26) | (mask_p[28] << 24) - | (mask_p[27] << 22) | (mask_p[26] << 20) - | (mask_p[25] << 18) | (mask_p[24] << 16) - | (mask_p[23] << 14) | (mask_p[22] << 12) - | (mask_p[21] << 10) | (mask_p[20] << 8) - | (mask_p[19] << 6) | (mask_p[18] << 4) - | (mask_p[17] << 2) | (mask_p[16] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - - tmp_mask = (mask_p[45] << 28) - | (mask_p[44] << 26) | (mask_p[43] << 24) - | (mask_p[42] << 22) | (mask_p[41] << 20) - | (mask_p[40] << 18) | (mask_p[39] << 16) - | (mask_p[38] << 14) | (mask_p[37] << 12) - | (mask_p[36] << 10) | (mask_p[35] << 8) - | (mask_p[34] << 6) | (mask_p[33] << 4) - | (mask_p[32] << 2) | (mask_p[31] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - - tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) - | (mask_p[59] << 26) | (mask_p[58] << 24) - | (mask_p[57] << 22) | (mask_p[56] << 20) - | (mask_p[55] << 18) | (mask_p[54] << 16) - | (mask_p[53] << 14) | (mask_p[52] << 12) - | (mask_p[51] << 10) | (mask_p[50] << 8) - | (mask_p[49] << 6) | (mask_p[48] << 4) - | (mask_p[47] << 2) | (mask_p[46] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); + ar5008_hw_cmn_spur_mitigate(ah, chan, bin); REGWRITE_BUFFER_FLUSH(ah); } @@ -426,10 +281,10 @@ static void ar9002_olc_init(struct ath_hw *ah) { u32 i; - if (!OLC_FOR_AR9280_20_LATER) + if (!OLC_FOR_AR9280_20_LATER(ah)) return; - if (OLC_FOR_AR9287_10_LATER) { + if (OLC_FOR_AR9287_10_LATER(ah)) { REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9, AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL); ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TXPC0, @@ -485,7 +340,7 @@ static void ar9002_hw_do_getnf(struct ath_hw *ah, if (IS_CHAN_HT40(ah->curchan)) nfarray[3] = sign_extend32(nf, 8); - if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) + if (!(ah->rxchainmask & BIT(1))) return; nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR9280_PHY_CH1_MINCCA_PWR); @@ -532,6 +387,7 @@ static void ar9002_hw_antdiv_comb_conf_get(struct ath_hw *ah, AR_PHY_9285_ANT_DIV_ALT_LNACONF_S; antconf->fast_div_bias = (regval & AR_PHY_9285_FAST_DIV_BIAS) >> AR_PHY_9285_FAST_DIV_BIAS_S; + antconf->lna1_lna2_switch_delta = -1; antconf->lna1_lna2_delta = -3; antconf->div_group = 0; } @@ -555,9 +411,73 @@ static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval); } +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + +static void ar9002_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) +{ + struct ath_btcoex_hw *btcoex = &ah->btcoex_hw; + u8 antdiv_ctrl1, antdiv_ctrl2; + u32 regval; + + if (enable) { + antdiv_ctrl1 = ATH_BT_COEX_ANTDIV_CONTROL1_ENABLE; + antdiv_ctrl2 = ATH_BT_COEX_ANTDIV_CONTROL2_ENABLE; + + /* + * Don't disable BT ant to allow BB to control SWCOM. + */ + btcoex->bt_coex_mode2 &= (~(AR_BT_DISABLE_BT_ANT)); + REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex->bt_coex_mode2); + + REG_WRITE(ah, AR_PHY_SWITCH_COM, ATH_BT_COEX_ANT_DIV_SWITCH_COM); + REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000); + } else { + /* + * Disable antenna diversity, use LNA1 only. + */ + antdiv_ctrl1 = ATH_BT_COEX_ANTDIV_CONTROL1_FIXED_A; + antdiv_ctrl2 = ATH_BT_COEX_ANTDIV_CONTROL2_FIXED_A; + + /* + * Disable BT Ant. to allow concurrent BT and WLAN receive. + */ + btcoex->bt_coex_mode2 |= AR_BT_DISABLE_BT_ANT; + REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex->bt_coex_mode2); + + /* + * Program SWCOM table to make sure RF switch always parks + * at BT side. + */ + REG_WRITE(ah, AR_PHY_SWITCH_COM, 0); + REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000); + } + + regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); + regval &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL)); + /* + * Clear ant_fast_div_bias [14:9] since for WB195, + * the main LNA is always LNA1. + */ + regval &= (~(AR_PHY_9285_FAST_DIV_BIAS)); + regval |= SM(antdiv_ctrl1, AR_PHY_9285_ANT_DIV_CTL); + regval |= SM(antdiv_ctrl2, AR_PHY_9285_ANT_DIV_ALT_LNACONF); + regval |= SM((antdiv_ctrl2 >> 2), AR_PHY_9285_ANT_DIV_MAIN_LNACONF); + regval |= SM((antdiv_ctrl1 >> 1), AR_PHY_9285_ANT_DIV_ALT_GAINTB); + regval |= SM((antdiv_ctrl1 >> 2), AR_PHY_9285_ANT_DIV_MAIN_GAINTB); + REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval); + + regval = REG_READ(ah, AR_PHY_CCK_DETECT); + regval &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); + regval |= SM((antdiv_ctrl1 >> 3), AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); + REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); +} + +#endif + static void ar9002_hw_spectral_scan_config(struct ath_hw *ah, struct ath_spec_scan *param) { + u32 repeat_bit; u8 count; if (!param->enabled) { @@ -568,25 +488,41 @@ static void ar9002_hw_spectral_scan_config(struct ath_hw *ah, REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA); REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE); + if (AR_SREV_9280(ah)) + repeat_bit = AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT; + else + repeat_bit = AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI; + if (param->short_repeat) - REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, - AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, repeat_bit); else - REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, - AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); + REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, repeat_bit); - /* on AR92xx, the highest bit of count will make the the chip send + /* on AR92xx, the highest bit of count will make the chip send * spectral samples endlessly. Check if this really was intended, * and fix otherwise. */ count = param->count; - if (param->endless) - count = 0x80; - else if (count & 0x80) + if (param->endless) { + if (AR_SREV_9280(ah)) + count = 0x80; + else + count = 0; + } else if (count & 0x80) count = 0x7f; + else if (!count) + count = 1; + + if (AR_SREV_9280(ah)) { + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_COUNT, count); + } else { + REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_COUNT_KIWI, count); + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT); + } - REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, - AR_PHY_SPECTRAL_SCAN_COUNT, count); REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_PERIOD, param->period); REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, @@ -616,6 +552,26 @@ static void ar9002_hw_spectral_scan_wait(struct ath_hw *ah) } } +static void ar9002_hw_tx99_start(struct ath_hw *ah, u32 qnum) +{ + REG_SET_BIT(ah, 0x9864, 0x7f000); + REG_SET_BIT(ah, 0x9924, 0x7f00fe); + REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); + REG_WRITE(ah, AR_CR, AR_CR_RXD); + REG_WRITE(ah, AR_DLCL_IFS(qnum), 0); + REG_WRITE(ah, AR_D_GBL_IFS_SIFS, 20); + REG_WRITE(ah, AR_D_GBL_IFS_EIFS, 20); + REG_WRITE(ah, AR_D_FPCTL, 0x10|qnum); + REG_WRITE(ah, AR_TIME_OUT, 0x00000400); + REG_WRITE(ah, AR_DRETRY_LIMIT(qnum), 0xffffffff); + REG_SET_BIT(ah, AR_QMISC(qnum), AR_Q_MISC_DCU_EARLY_TERM_REQ); +} + +static void ar9002_hw_tx99_stop(struct ath_hw *ah) +{ + REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); +} + void ar9002_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); @@ -634,5 +590,11 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah) ops->spectral_scan_trigger = ar9002_hw_spectral_scan_trigger; ops->spectral_scan_wait = ar9002_hw_spectral_scan_wait; +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + ops->set_bt_ant_diversity = ar9002_hw_set_bt_ant_diversity; +#endif + ops->tx99_start = ar9002_hw_tx99_start; + ops->tx99_stop = ar9002_hw_tx99_stop; + ar9002_hw_set_nf_limits(ah); } diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h index f9eb2c357169..2b58245f774a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h @@ -177,8 +177,11 @@ #define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8 #define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000 /* Number of reports, reg 68, bits 16-23*/ #define AR_PHY_SPECTRAL_SCAN_COUNT_S 16 +#define AR_PHY_SPECTRAL_SCAN_COUNT_KIWI 0x0FFF0000 /* Number of reports, reg 68, bits 16-27*/ +#define AR_PHY_SPECTRAL_SCAN_COUNT_KIWI_S 16 #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 /* Short repeat, reg 68, bit 24*/ -#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 /* Short repeat, reg 68, bit 24*/ +#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI 0x10000000 /* Short repeat, reg 68, bit 28*/ +#define AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT 0x40000000 #define AR_PHY_RX_DELAY 0x9914 #define AR_PHY_SEARCH_START_DELAY 0x9918 @@ -317,13 +320,15 @@ #define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S 29 #define AR_PHY_9285_ANT_DIV_MAIN_GAINTB 0x40000000 #define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S 30 -#define AR_PHY_9285_ANT_DIV_LNA1 2 -#define AR_PHY_9285_ANT_DIV_LNA2 1 -#define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2 3 -#define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0 #define AR_PHY_9285_ANT_DIV_GAINTB_0 0 #define AR_PHY_9285_ANT_DIV_GAINTB_1 1 +#define ATH_BT_COEX_ANTDIV_CONTROL1_ENABLE 0x0b +#define ATH_BT_COEX_ANTDIV_CONTROL2_ENABLE 0x09 +#define ATH_BT_COEX_ANTDIV_CONTROL1_FIXED_A 0x04 +#define ATH_BT_COEX_ANTDIV_CONTROL2_FIXED_A 0x09 +#define ATH_BT_COEX_ANT_DIV_SWITCH_COM 0x66666666 + #define AR_PHY_EXT_CCA0 0x99b8 #define AR_PHY_EXT_CCA0_THRESH62 0x000000FF #define AR_PHY_EXT_CCA0_THRESH62_S 0 @@ -608,8 +613,8 @@ #define AR_PHY_CCA_MIN_GOOD_VAL_9271_2GHZ -127 #define AR_PHY_CCA_MAX_GOOD_VAL_9271_2GHZ -116 -#define AR_PHY_CCA_NOM_VAL_9287_2GHZ -120 +#define AR_PHY_CCA_NOM_VAL_9287_2GHZ -112 #define AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ -127 -#define AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ -110 +#define AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ -97 #endif diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 7546b9a7dcbf..16d5c0c5e2a8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -303,7 +303,7 @@ static const u32 ar9300_2p2_mac_postamble[][5] = { {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, + {0x00008120, 0x18f04800, 0x18f04800, 0x18f04810, 0x18f04810}, {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, }; @@ -331,7 +331,7 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = { {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946220, 0xcf946220}, {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -351,8 +351,8 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, + {0x0000a2d0, 0x00041983, 0x00041983, 0x00041981, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, @@ -378,9 +378,9 @@ static const u32 ar9300_2p2_baseband_core[][2] = { {0x00009814, 0x9280c00a}, {0x00009818, 0x00000000}, {0x0000981c, 0x00020028}, - {0x00009834, 0x6400a290}, + {0x00009834, 0x6400a190}, {0x00009838, 0x0108ecff}, - {0x0000983c, 0x0d000600}, + {0x0000983c, 0x14000600}, {0x00009880, 0x201fff00}, {0x00009884, 0x00001042}, {0x000098a4, 0x00200400}, @@ -401,7 +401,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = { {0x00009d04, 0x40206c10}, {0x00009d08, 0x009c4060}, {0x00009d0c, 0x9883800a}, - {0x00009d10, 0x01834061}, + {0x00009d10, 0x01884061}, {0x00009d14, 0x00c0040b}, {0x00009d18, 0x00000000}, {0x00009e08, 0x0038230c}, @@ -410,7 +410,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x0d261800}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, {0x00009e54, 0x00000000}, @@ -459,7 +459,7 @@ static const u32 ar9300_2p2_baseband_core[][2] = { {0x0000a3e8, 0x20202020}, {0x0000a3ec, 0x20202020}, {0x0000a3f0, 0x00000000}, - {0x0000a3f4, 0x00000246}, + {0x0000a3f4, 0x00000000}, {0x0000a3f8, 0x0c9bd380}, {0x0000a3fc, 0x000f0f01}, {0x0000a400, 0x8fa91f01}, @@ -534,107 +534,107 @@ static const u32 ar9300_2p2_baseband_core[][2] = { static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, - {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, - {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, - {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, - {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, - {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, - {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, - {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, - {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, - {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, - {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, - {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, - {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, - {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, - {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, - {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, - {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, - {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, - {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, - {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, - {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, - {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, - {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, - {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, - {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, - {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, - {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, - {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, - {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, - {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, - {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, - {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, - {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, - {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, - {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, - {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, - {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, - {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, - {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, - {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, - {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, - {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, - {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, - {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, - {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, - {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, - {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, - {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, - {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400}, + {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402}, + {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404}, + {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640}, + {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x15800028, 0x15800028, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1b80002b, 0x1b80002b, 0x12800400, 0x12800400}, + {0x0000a598, 0x1f820028, 0x1f820028, 0x16800402, 0x16800402}, + {0x0000a59c, 0x2582002b, 0x2582002b, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2a84002a, 0x2a84002a, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2e86002a, 0x2e86002a, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x3382202d, 0x3382202d, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3884202c, 0x3884202c, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3c86202c, 0x3c86202c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4188202d, 0x4188202d, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4586402d, 0x4586402d, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4986222d, 0x4986222d, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4d862231, 0x4d862231, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x50882231, 0x50882231, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5688422e, 0x5688422e, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5e88442e, 0x5e88442e, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x628a4431, 0x628a4431, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x648a4432, 0x648a4432, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x688a4434, 0x688a4434, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x6c8a6434, 0x6c8a6434, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x6f8a6633, 0x6f8a6633, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, - {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, - {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, - {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, - {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000}, + {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501}, + {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501}, + {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; @@ -644,7 +644,7 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = { {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a410, 0x000050d4, 0x000050d4, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, @@ -1086,8 +1086,8 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = { {0x0000b074, 0x00000000}, {0x0000b078, 0x00000000}, {0x0000b07c, 0x00000000}, - {0x0000b080, 0x2a2d2f32}, - {0x0000b084, 0x21232328}, + {0x0000b080, 0x23232323}, + {0x0000b084, 0x21232323}, {0x0000b088, 0x19191c1e}, {0x0000b08c, 0x12141417}, {0x0000b090, 0x07070e0e}, @@ -1385,9 +1385,9 @@ static const u32 ar9300_2p2_mac_core[][2] = { {0x000081f8, 0x00000000}, {0x000081fc, 0x00000000}, {0x00008240, 0x00100000}, - {0x00008244, 0x0010f424}, + {0x00008244, 0x0010f400}, {0x00008248, 0x00000800}, - {0x0000824c, 0x0001e848}, + {0x0000824c, 0x0001e800}, {0x00008250, 0x00000000}, {0x00008254, 0x00000000}, {0x00008258, 0x00000000}, @@ -1724,18 +1724,18 @@ static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2[][2] = { {0x00004044, 0x00000000}, }; -static const u32 ar9300PciePhy_clkreq_enable_L1_2p2[][2] = { +static const u32 ar9300_2p2_baseband_core_txfir_coeff_japan_2484[][2] = { /* Addr allmodes */ - {0x00004040, 0x08253e5e}, - {0x00004040, 0x0008003b}, - {0x00004044, 0x00000000}, + {0x0000a398, 0x00000000}, + {0x0000a39c, 0x6f7f0301}, + {0x0000a3a0, 0xca9228ee}, }; -static const u32 ar9300PciePhy_clkreq_disable_L1_2p2[][2] = { - /* Addr allmodes */ - {0x00004040, 0x08213e5e}, - {0x00004040, 0x0008003b}, - {0x00004044, 0x00000000}, +static const u32 ar9300_2p2_baseband_postamble_dfs_channel[][3] = { + /* Addr 5G 2G */ + {0x00009824, 0x5ac668d0, 0x5ac668d0}, + {0x00009e0c, 0x6d4000e2, 0x6d4000e2}, + {0x00009e14, 0x37b9625e, 0x37b9625e}, }; #endif /* INITVALS_9003_2P2_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c new file mode 100644 index 000000000000..45a7ca660f47 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c @@ -0,0 +1,598 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "hw.h" +#include "hw-ops.h" +#include "ar9003_mci.h" +#include "ar9003_aic.h" +#include "ar9003_phy.h" +#include "reg_aic.h" + +static const u8 com_att_db_table[ATH_AIC_MAX_COM_ATT_DB_TABLE] = { + 0, 3, 9, 15, 21, 27 +}; + +static const u16 aic_lin_table[ATH_AIC_MAX_AIC_LIN_TABLE] = { + 8191, 7300, 6506, 5799, 5168, 4606, 4105, 3659, + 3261, 2906, 2590, 2309, 2057, 1834, 1634, 1457, + 1298, 1157, 1031, 919, 819, 730, 651, 580, + 517, 461, 411, 366, 326, 291, 259, 231, + 206, 183, 163, 146, 130, 116, 103, 92, + 82, 73, 65, 58, 52, 46, 41, 37, + 33, 29, 26, 23, 21, 18, 16, 15, + 13, 12, 10, 9, 8, 7, 7, 6, + 5, 5, 4, 4, 3 +}; + +static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah) +{ + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; + + /* + * Disable AIC for now, until we have all the + * HW code and the driver-layer support ready. + */ + return false; + + if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_AIC) + return false; + + return true; +} + +static int16_t ar9003_aic_find_valid(bool *cal_sram_valid, + bool dir, u8 index) +{ + int16_t i; + + if (dir) { + for (i = index + 1; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + if (cal_sram_valid[i]) + break; + } + } else { + for (i = index - 1; i >= 0; i--) { + if (cal_sram_valid[i]) + break; + } + } + + if ((i >= ATH_AIC_MAX_BT_CHANNEL) || (i < 0)) + i = -1; + + return i; +} + +/* + * type 0: aic_lin_table, 1: com_att_db_table + */ +static int16_t ar9003_aic_find_index(u8 type, int16_t value) +{ + int16_t i = -1; + + if (type == 0) { + for (i = ATH_AIC_MAX_AIC_LIN_TABLE - 1; i >= 0; i--) { + if (aic_lin_table[i] >= value) + break; + } + } else if (type == 1) { + for (i = 0; i < ATH_AIC_MAX_COM_ATT_DB_TABLE; i++) { + if (com_att_db_table[i] > value) { + i--; + break; + } + } + + if (i >= ATH_AIC_MAX_COM_ATT_DB_TABLE) + i = -1; + } + + return i; +} + +static void ar9003_aic_gain_table(struct ath_hw *ah) +{ + u32 aic_atten_word[19], i; + + /* Config LNA gain difference */ + REG_WRITE(ah, AR_PHY_BT_COEX_4, 0x2c200a00); + REG_WRITE(ah, AR_PHY_BT_COEX_5, 0x5c4e4438); + + /* Program gain table */ + aic_atten_word[0] = (0x1 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x0 & 0xf) << 5 | + (0x1f & 0x1f); /* -01 dB: 4'd1, 5'd31, 00 dB: 4'd0, 5'd31 */ + aic_atten_word[1] = (0x3 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x2 & 0xf) << 5 | + (0x1f & 0x1f); /* -03 dB: 4'd3, 5'd31, -02 dB: 4'd2, 5'd31 */ + aic_atten_word[2] = (0x5 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x4 & 0xf) << 5 | + (0x1f & 0x1f); /* -05 dB: 4'd5, 5'd31, -04 dB: 4'd4, 5'd31 */ + aic_atten_word[3] = (0x1 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x0 & 0xf) << 5 | + (0x1e & 0x1f); /* -07 dB: 4'd1, 5'd30, -06 dB: 4'd0, 5'd30 */ + aic_atten_word[4] = (0x3 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x2 & 0xf) << 5 | + (0x1e & 0x1f); /* -09 dB: 4'd3, 5'd30, -08 dB: 4'd2, 5'd30 */ + aic_atten_word[5] = (0x5 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x4 & 0xf) << 5 | + (0x1e & 0x1f); /* -11 dB: 4'd5, 5'd30, -10 dB: 4'd4, 5'd30 */ + aic_atten_word[6] = (0x1 & 0xf) << 14 | (0xf & 0x1f) << 9 | (0x0 & 0xf) << 5 | + (0xf & 0x1f); /* -13 dB: 4'd1, 5'd15, -12 dB: 4'd0, 5'd15 */ + aic_atten_word[7] = (0x3 & 0xf) << 14 | (0xf & 0x1f) << 9 | (0x2 & 0xf) << 5 | + (0xf & 0x1f); /* -15 dB: 4'd3, 5'd15, -14 dB: 4'd2, 5'd15 */ + aic_atten_word[8] = (0x5 & 0xf) << 14 | (0xf & 0x1f) << 9 | (0x4 & 0xf) << 5 | + (0xf & 0x1f); /* -17 dB: 4'd5, 5'd15, -16 dB: 4'd4, 5'd15 */ + aic_atten_word[9] = (0x1 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x0 & 0xf) << 5 | + (0x7 & 0x1f); /* -19 dB: 4'd1, 5'd07, -18 dB: 4'd0, 5'd07 */ + aic_atten_word[10] = (0x3 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x2 & 0xf) << 5 | + (0x7 & 0x1f); /* -21 dB: 4'd3, 5'd07, -20 dB: 4'd2, 5'd07 */ + aic_atten_word[11] = (0x5 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x4 & 0xf) << 5 | + (0x7 & 0x1f); /* -23 dB: 4'd5, 5'd07, -22 dB: 4'd4, 5'd07 */ + aic_atten_word[12] = (0x7 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x6 & 0xf) << 5 | + (0x7 & 0x1f); /* -25 dB: 4'd7, 5'd07, -24 dB: 4'd6, 5'd07 */ + aic_atten_word[13] = (0x3 & 0xf) << 14 | (0x3 & 0x1f) << 9 | (0x2 & 0xf) << 5 | + (0x3 & 0x1f); /* -27 dB: 4'd3, 5'd03, -26 dB: 4'd2, 5'd03 */ + aic_atten_word[14] = (0x5 & 0xf) << 14 | (0x3 & 0x1f) << 9 | (0x4 & 0xf) << 5 | + (0x3 & 0x1f); /* -29 dB: 4'd5, 5'd03, -28 dB: 4'd4, 5'd03 */ + aic_atten_word[15] = (0x1 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x0 & 0xf) << 5 | + (0x1 & 0x1f); /* -31 dB: 4'd1, 5'd01, -30 dB: 4'd0, 5'd01 */ + aic_atten_word[16] = (0x3 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x2 & 0xf) << 5 | + (0x1 & 0x1f); /* -33 dB: 4'd3, 5'd01, -32 dB: 4'd2, 5'd01 */ + aic_atten_word[17] = (0x5 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x4 & 0xf) << 5 | + (0x1 & 0x1f); /* -35 dB: 4'd5, 5'd01, -34 dB: 4'd4, 5'd01 */ + aic_atten_word[18] = (0x7 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x6 & 0xf) << 5 | + (0x1 & 0x1f); /* -37 dB: 4'd7, 5'd01, -36 dB: 4'd6, 5'd01 */ + + /* Write to Gain table with auto increment enabled. */ + REG_WRITE(ah, (AR_PHY_AIC_SRAM_ADDR_B0 + 0x3000), + (ATH_AIC_SRAM_AUTO_INCREMENT | + ATH_AIC_SRAM_GAIN_TABLE_OFFSET)); + + for (i = 0; i < 19; i++) { + REG_WRITE(ah, (AR_PHY_AIC_SRAM_DATA_B0 + 0x3000), + aic_atten_word[i]); + } +} + +static u8 ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count) +{ + struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; + int i; + + /* Write to Gain table with auto increment enabled. */ + REG_WRITE(ah, (AR_PHY_AIC_SRAM_ADDR_B0 + 0x3000), + (ATH_AIC_SRAM_AUTO_INCREMENT | + ATH_AIC_SRAM_CAL_OFFSET)); + + for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + REG_WRITE(ah, (AR_PHY_AIC_SRAM_DATA_B0 + 0x3000), 0); + aic->aic_sram[i] = 0; + } + + REG_WRITE(ah, AR_PHY_AIC_CTRL_0_B0, + (SM(0, AR_PHY_AIC_MON_ENABLE) | + SM(127, AR_PHY_AIC_CAL_MAX_HOP_COUNT) | + SM(min_valid_count, AR_PHY_AIC_CAL_MIN_VALID_COUNT) | + SM(37, AR_PHY_AIC_F_WLAN) | + SM(1, AR_PHY_AIC_CAL_CH_VALID_RESET) | + SM(0, AR_PHY_AIC_CAL_ENABLE) | + SM(0x40, AR_PHY_AIC_BTTX_PWR_THR) | + SM(0, AR_PHY_AIC_ENABLE))); + + REG_WRITE(ah, AR_PHY_AIC_CTRL_0_B1, + (SM(0, AR_PHY_AIC_MON_ENABLE) | + SM(1, AR_PHY_AIC_CAL_CH_VALID_RESET) | + SM(0, AR_PHY_AIC_CAL_ENABLE) | + SM(0x40, AR_PHY_AIC_BTTX_PWR_THR) | + SM(0, AR_PHY_AIC_ENABLE))); + + REG_WRITE(ah, AR_PHY_AIC_CTRL_1_B0, + (SM(8, AR_PHY_AIC_CAL_BT_REF_DELAY) | + SM(0, AR_PHY_AIC_BT_IDLE_CFG) | + SM(1, AR_PHY_AIC_STDBY_COND) | + SM(37, AR_PHY_AIC_STDBY_ROT_ATT_DB) | + SM(5, AR_PHY_AIC_STDBY_COM_ATT_DB) | + SM(15, AR_PHY_AIC_RSSI_MAX) | + SM(0, AR_PHY_AIC_RSSI_MIN))); + + REG_WRITE(ah, AR_PHY_AIC_CTRL_1_B1, + (SM(15, AR_PHY_AIC_RSSI_MAX) | + SM(0, AR_PHY_AIC_RSSI_MIN))); + + REG_WRITE(ah, AR_PHY_AIC_CTRL_2_B0, + (SM(44, AR_PHY_AIC_RADIO_DELAY) | + SM(8, AR_PHY_AIC_CAL_STEP_SIZE_CORR) | + SM(12, AR_PHY_AIC_CAL_ROT_IDX_CORR) | + SM(2, AR_PHY_AIC_CAL_CONV_CHECK_FACTOR) | + SM(5, AR_PHY_AIC_ROT_IDX_COUNT_MAX) | + SM(0, AR_PHY_AIC_CAL_SYNTH_TOGGLE) | + SM(0, AR_PHY_AIC_CAL_SYNTH_AFTER_BTRX) | + SM(200, AR_PHY_AIC_CAL_SYNTH_SETTLING))); + + REG_WRITE(ah, AR_PHY_AIC_CTRL_3_B0, + (SM(2, AR_PHY_AIC_MON_MAX_HOP_COUNT) | + SM(1, AR_PHY_AIC_MON_MIN_STALE_COUNT) | + SM(1, AR_PHY_AIC_MON_PWR_EST_LONG) | + SM(2, AR_PHY_AIC_MON_PD_TALLY_SCALING) | + SM(10, AR_PHY_AIC_MON_PERF_THR) | + SM(2, AR_PHY_AIC_CAL_TARGET_MAG_SETTING) | + SM(1, AR_PHY_AIC_CAL_PERF_CHECK_FACTOR) | + SM(1, AR_PHY_AIC_CAL_PWR_EST_LONG))); + + REG_WRITE(ah, AR_PHY_AIC_CTRL_4_B0, + (SM(2, AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO) | + SM(3, AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO) | + SM(0, AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING) | + SM(2, AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF) | + SM(1, AR_PHY_AIC_CAL_COM_ATT_DB_FIXED))); + + REG_WRITE(ah, AR_PHY_AIC_CTRL_4_B1, + (SM(2, AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO) | + SM(3, AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO) | + SM(0, AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING) | + SM(2, AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF) | + SM(1, AR_PHY_AIC_CAL_COM_ATT_DB_FIXED))); + + ar9003_aic_gain_table(ah); + + /* Need to enable AIC reference signal in BT modem. */ + REG_WRITE(ah, ATH_AIC_BT_JUPITER_CTRL, + (REG_READ(ah, ATH_AIC_BT_JUPITER_CTRL) | + ATH_AIC_BT_AIC_ENABLE)); + + aic->aic_cal_start_time = REG_READ(ah, AR_TSF_L32); + + /* Start calibration */ + REG_CLR_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE); + REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_CH_VALID_RESET); + REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE); + + aic->aic_caled_chan = 0; + aic->aic_cal_state = AIC_CAL_STATE_STARTED; + + return aic->aic_cal_state; +} + +static bool ar9003_aic_cal_post_process(struct ath_hw *ah) +{ + struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; + bool cal_sram_valid[ATH_AIC_MAX_BT_CHANNEL]; + struct ath_aic_out_info aic_sram[ATH_AIC_MAX_BT_CHANNEL]; + u32 dir_path_gain_idx, quad_path_gain_idx, value; + u32 fixed_com_att_db; + int8_t dir_path_sign, quad_path_sign; + int16_t i; + bool ret = true; + + memset(&cal_sram_valid, 0, sizeof(cal_sram_valid)); + memset(&aic_sram, 0, sizeof(aic_sram)); + + for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + struct ath_aic_sram_info sram; + value = aic->aic_sram[i]; + + cal_sram_valid[i] = sram.valid = + MS(value, AR_PHY_AIC_SRAM_VALID); + sram.rot_quad_att_db = + MS(value, AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB); + sram.vga_quad_sign = + MS(value, AR_PHY_AIC_SRAM_VGA_QUAD_SIGN); + sram.rot_dir_att_db = + MS(value, AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB); + sram.vga_dir_sign = + MS(value, AR_PHY_AIC_SRAM_VGA_DIR_SIGN); + sram.com_att_6db = + MS(value, AR_PHY_AIC_SRAM_COM_ATT_6DB); + + if (sram.valid) { + dir_path_gain_idx = sram.rot_dir_att_db + + com_att_db_table[sram.com_att_6db]; + quad_path_gain_idx = sram.rot_quad_att_db + + com_att_db_table[sram.com_att_6db]; + + dir_path_sign = (sram.vga_dir_sign) ? 1 : -1; + quad_path_sign = (sram.vga_quad_sign) ? 1 : -1; + + aic_sram[i].dir_path_gain_lin = dir_path_sign * + aic_lin_table[dir_path_gain_idx]; + aic_sram[i].quad_path_gain_lin = quad_path_sign * + aic_lin_table[quad_path_gain_idx]; + } + } + + for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + int16_t start_idx, end_idx; + + if (cal_sram_valid[i]) + continue; + + start_idx = ar9003_aic_find_valid(cal_sram_valid, 0, i); + end_idx = ar9003_aic_find_valid(cal_sram_valid, 1, i); + + if (start_idx < 0) { + /* extrapolation */ + start_idx = end_idx; + end_idx = ar9003_aic_find_valid(cal_sram_valid, 1, start_idx); + + if (end_idx < 0) { + ret = false; + break; + } + + aic_sram[i].dir_path_gain_lin = + ((aic_sram[start_idx].dir_path_gain_lin - + aic_sram[end_idx].dir_path_gain_lin) * + (start_idx - i) + ((end_idx - i) >> 1)) / + (end_idx - i) + + aic_sram[start_idx].dir_path_gain_lin; + aic_sram[i].quad_path_gain_lin = + ((aic_sram[start_idx].quad_path_gain_lin - + aic_sram[end_idx].quad_path_gain_lin) * + (start_idx - i) + ((end_idx - i) >> 1)) / + (end_idx - i) + + aic_sram[start_idx].quad_path_gain_lin; + } + + if (end_idx < 0) { + /* extrapolation */ + end_idx = ar9003_aic_find_valid(cal_sram_valid, 0, start_idx); + + if (end_idx < 0) { + ret = false; + break; + } + + aic_sram[i].dir_path_gain_lin = + ((aic_sram[start_idx].dir_path_gain_lin - + aic_sram[end_idx].dir_path_gain_lin) * + (i - start_idx) + ((start_idx - end_idx) >> 1)) / + (start_idx - end_idx) + + aic_sram[start_idx].dir_path_gain_lin; + aic_sram[i].quad_path_gain_lin = + ((aic_sram[start_idx].quad_path_gain_lin - + aic_sram[end_idx].quad_path_gain_lin) * + (i - start_idx) + ((start_idx - end_idx) >> 1)) / + (start_idx - end_idx) + + aic_sram[start_idx].quad_path_gain_lin; + + } else if (start_idx >= 0){ + /* interpolation */ + aic_sram[i].dir_path_gain_lin = + (((end_idx - i) * aic_sram[start_idx].dir_path_gain_lin) + + ((i - start_idx) * aic_sram[end_idx].dir_path_gain_lin) + + ((end_idx - start_idx) >> 1)) / + (end_idx - start_idx); + aic_sram[i].quad_path_gain_lin = + (((end_idx - i) * aic_sram[start_idx].quad_path_gain_lin) + + ((i - start_idx) * aic_sram[end_idx].quad_path_gain_lin) + + ((end_idx - start_idx) >> 1))/ + (end_idx - start_idx); + } + } + + /* From dir/quad_path_gain_lin to sram. */ + i = ar9003_aic_find_valid(cal_sram_valid, 1, 0); + if (i < 0) { + i = 0; + ret = false; + } + fixed_com_att_db = com_att_db_table[MS(aic->aic_sram[i], + AR_PHY_AIC_SRAM_COM_ATT_6DB)]; + + for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + int16_t rot_dir_path_att_db, rot_quad_path_att_db; + struct ath_aic_sram_info sram; + + sram.vga_dir_sign = + (aic_sram[i].dir_path_gain_lin >= 0) ? 1 : 0; + sram.vga_quad_sign = + (aic_sram[i].quad_path_gain_lin >= 0) ? 1 : 0; + + rot_dir_path_att_db = + ar9003_aic_find_index(0, abs(aic_sram[i].dir_path_gain_lin)) - + fixed_com_att_db; + rot_quad_path_att_db = + ar9003_aic_find_index(0, abs(aic_sram[i].quad_path_gain_lin)) - + fixed_com_att_db; + + sram.com_att_6db = + ar9003_aic_find_index(1, fixed_com_att_db); + + sram.valid = true; + + sram.rot_dir_att_db = + clamp(rot_dir_path_att_db, (int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB, + ATH_AIC_MAX_ROT_DIR_ATT_DB); + sram.rot_quad_att_db = + clamp(rot_quad_path_att_db, (int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB, + ATH_AIC_MAX_ROT_QUAD_ATT_DB); + + aic->aic_sram[i] = (SM(sram.vga_dir_sign, + AR_PHY_AIC_SRAM_VGA_DIR_SIGN) | + SM(sram.vga_quad_sign, + AR_PHY_AIC_SRAM_VGA_QUAD_SIGN) | + SM(sram.com_att_6db, + AR_PHY_AIC_SRAM_COM_ATT_6DB) | + SM(sram.valid, + AR_PHY_AIC_SRAM_VALID) | + SM(sram.rot_dir_att_db, + AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB) | + SM(sram.rot_quad_att_db, + AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB)); + } + + return ret; +} + +static void ar9003_aic_cal_done(struct ath_hw *ah) +{ + struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; + + /* Disable AIC reference signal in BT modem. */ + REG_WRITE(ah, ATH_AIC_BT_JUPITER_CTRL, + (REG_READ(ah, ATH_AIC_BT_JUPITER_CTRL) & + ~ATH_AIC_BT_AIC_ENABLE)); + + if (ar9003_aic_cal_post_process(ah)) + aic->aic_cal_state = AIC_CAL_STATE_DONE; + else + aic->aic_cal_state = AIC_CAL_STATE_ERROR; +} + +static u8 ar9003_aic_cal_continue(struct ath_hw *ah, bool cal_once) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; + struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; + int i, num_chan; + + num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN); + + if (!num_chan) { + aic->aic_cal_state = AIC_CAL_STATE_ERROR; + return aic->aic_cal_state; + } + + if (cal_once) { + for (i = 0; i < 10000; i++) { + if ((REG_READ(ah, AR_PHY_AIC_CTRL_0_B1) & + AR_PHY_AIC_CAL_ENABLE) == 0) + break; + + udelay(100); + } + } + + /* + * Use AR_PHY_AIC_CAL_ENABLE bit instead of AR_PHY_AIC_CAL_DONE. + * Sometimes CAL_DONE bit is not asserted. + */ + if ((REG_READ(ah, AR_PHY_AIC_CTRL_0_B1) & + AR_PHY_AIC_CAL_ENABLE) != 0) { + ath_dbg(common, MCI, "AIC cal is not done after 40ms"); + goto exit; + } + + REG_WRITE(ah, AR_PHY_AIC_SRAM_ADDR_B1, + (ATH_AIC_SRAM_CAL_OFFSET | ATH_AIC_SRAM_AUTO_INCREMENT)); + + for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + u32 value; + + value = REG_READ(ah, AR_PHY_AIC_SRAM_DATA_B1); + + if (value & 0x01) { + if (aic->aic_sram[i] == 0) + aic->aic_caled_chan++; + + aic->aic_sram[i] = value; + + if (!cal_once) + break; + } + } + + if ((aic->aic_caled_chan >= num_chan) || cal_once) { + ar9003_aic_cal_done(ah); + } else { + /* Start calibration */ + REG_CLR_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE); + REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, + AR_PHY_AIC_CAL_CH_VALID_RESET); + REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE); + } +exit: + return aic->aic_cal_state; + +} + +u8 ar9003_aic_calibration(struct ath_hw *ah) +{ + struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; + u8 cal_ret = AIC_CAL_STATE_ERROR; + + switch (aic->aic_cal_state) { + case AIC_CAL_STATE_IDLE: + cal_ret = ar9003_aic_cal_start(ah, 1); + break; + case AIC_CAL_STATE_STARTED: + cal_ret = ar9003_aic_cal_continue(ah, false); + break; + case AIC_CAL_STATE_DONE: + cal_ret = AIC_CAL_STATE_DONE; + break; + default: + break; + } + + return cal_ret; +} + +u8 ar9003_aic_start_normal(struct ath_hw *ah) +{ + struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; + int16_t i; + + if (aic->aic_cal_state != AIC_CAL_STATE_DONE) + return 1; + + ar9003_aic_gain_table(ah); + + REG_WRITE(ah, AR_PHY_AIC_SRAM_ADDR_B1, ATH_AIC_SRAM_AUTO_INCREMENT); + + for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + REG_WRITE(ah, AR_PHY_AIC_SRAM_DATA_B1, aic->aic_sram[i]); + } + + /* FIXME: Replace these with proper register names */ + REG_WRITE(ah, 0xa6b0, 0x80); + REG_WRITE(ah, 0xa6b4, 0x5b2df0); + REG_WRITE(ah, 0xa6b8, 0x10762cc8); + REG_WRITE(ah, 0xa6bc, 0x1219a4b); + REG_WRITE(ah, 0xa6c0, 0x1e01); + REG_WRITE(ah, 0xb6b4, 0xf0); + REG_WRITE(ah, 0xb6c0, 0x1e01); + REG_WRITE(ah, 0xb6b0, 0x81); + REG_WRITE(ah, AR_PHY_65NM_CH1_RXTX4, 0x40000000); + + aic->aic_enabled = true; + + return 0; +} + +u8 ar9003_aic_cal_reset(struct ath_hw *ah) +{ + struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; + + aic->aic_cal_state = AIC_CAL_STATE_IDLE; + return aic->aic_cal_state; +} + +u8 ar9003_aic_calibration_single(struct ath_hw *ah) +{ + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; + u8 cal_ret; + int num_chan; + + num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN); + + (void) ar9003_aic_cal_start(ah, num_chan); + cal_ret = ar9003_aic_cal_continue(ah, true); + + return cal_ret; +} + +void ar9003_hw_attach_aic_ops(struct ath_hw *ah) +{ + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + + priv_ops->is_aic_enabled = ar9003_hw_is_aic_enabled; +} diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.h b/drivers/net/wireless/ath/ath9k/ar9003_aic.h new file mode 100644 index 000000000000..9512c63799f2 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef AR9003_AIC_H +#define AR9003_AIC_H + +#define ATH_AIC_MAX_COM_ATT_DB_TABLE 6 +#define ATH_AIC_MAX_AIC_LIN_TABLE 69 +#define ATH_AIC_MIN_ROT_DIR_ATT_DB 0 +#define ATH_AIC_MIN_ROT_QUAD_ATT_DB 0 +#define ATH_AIC_MAX_ROT_DIR_ATT_DB 37 +#define ATH_AIC_MAX_ROT_QUAD_ATT_DB 37 +#define ATH_AIC_SRAM_AUTO_INCREMENT 0x80000000 +#define ATH_AIC_SRAM_GAIN_TABLE_OFFSET 0x280 +#define ATH_AIC_SRAM_CAL_OFFSET 0x140 +#define ATH_AIC_SRAM_OFFSET 0x00 +#define ATH_AIC_MEAS_MAG_THRESH 20 +#define ATH_AIC_BT_JUPITER_CTRL 0x66820 +#define ATH_AIC_BT_AIC_ENABLE 0x02 + +enum aic_cal_state { + AIC_CAL_STATE_IDLE = 0, + AIC_CAL_STATE_STARTED, + AIC_CAL_STATE_DONE, + AIC_CAL_STATE_ERROR +}; + +struct ath_aic_sram_info { + bool valid:1; + bool vga_quad_sign:1; + bool vga_dir_sign:1; + u8 rot_quad_att_db; + u8 rot_dir_att_db; + u8 com_att_6db; +}; + +struct ath_aic_out_info { + int16_t dir_path_gain_lin; + int16_t quad_path_gain_lin; +}; + +u8 ar9003_aic_calibration(struct ath_hw *ah); +u8 ar9003_aic_start_normal(struct ath_hw *ah); +u8 ar9003_aic_cal_reset(struct ath_hw *ah); +u8 ar9003_aic_calibration_single(struct ath_hw *ah); + +#endif /* AR9003_AIC_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_buffalo_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_buffalo_initvals.h new file mode 100644 index 000000000000..59cf738f70df --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_buffalo_initvals.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2013 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INITVALS_9003_BUFFALO_H +#define INITVALS_9003_BUFFALO_H + +static const u32 ar9300Modes_high_power_tx_gain_table_buffalo[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, + {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, + {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, + {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, + {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, + {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, + {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, + {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +}; + +#endif /* INITVALS_9003_BUFFALO_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 6988e1d081f2..2224cb74b1d4 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -23,10 +23,11 @@ #define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT #define MAX_MAG_DELTA 11 #define MAX_PHS_DELTA 10 +#define MAXIQCAL 3 struct coeff { - int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; - int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; + int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; + int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; int iqc_coeff[2]; }; @@ -74,59 +75,57 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal) { struct ath9k_hw_cal_data *caldata = ah->caldata; - /* Cal is assumed not done until explicitly set below */ - bool iscaldone = false; + const struct ath9k_percal_data *cur_caldata = currCal->calData; /* Calibration in progress. */ if (currCal->calState == CAL_RUNNING) { /* Check to see if it has finished. */ - if (!(REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) { + if (REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL) + return false; + + /* + * Accumulate cal measures for active chains + */ + cur_caldata->calCollect(ah); + ah->cal_samples++; + + if (ah->cal_samples >= cur_caldata->calNumSamples) { + unsigned int i, numChains = 0; + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (rxchainmask & (1 << i)) + numChains++; + } + /* - * Accumulate cal measures for active chains + * Process accumulated data */ - currCal->calData->calCollect(ah); - ah->cal_samples++; - - if (ah->cal_samples >= - currCal->calData->calNumSamples) { - unsigned int i, numChains = 0; - for (i = 0; i < AR9300_MAX_CHAINS; i++) { - if (rxchainmask & (1 << i)) - numChains++; - } - - /* - * Process accumulated data - */ - currCal->calData->calPostProc(ah, numChains); + cur_caldata->calPostProc(ah, numChains); - /* Calibration has finished. */ - caldata->CalValid |= currCal->calData->calType; - currCal->calState = CAL_DONE; - iscaldone = true; - } else { + /* Calibration has finished. */ + caldata->CalValid |= cur_caldata->calType; + currCal->calState = CAL_DONE; + return true; + } else { /* * Set-up collection of another sub-sample until we * get desired number */ ar9003_hw_setup_calibration(ah, currCal); - } } - } else if (!(caldata->CalValid & currCal->calData->calType)) { + } else if (!(caldata->CalValid & cur_caldata->calType)) { /* If current cal is marked invalid in channel, kick it off */ ath9k_hw_reset_calibration(ah, currCal); } - return iscaldone; + return false; } -static bool ar9003_hw_calibrate(struct ath_hw *ah, - struct ath9k_channel *chan, - u8 rxchainmask, - bool longcal) +static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal) { bool iscaldone = true; struct ath9k_cal_list *currCal = ah->cal_list_curr; + int ret; /* * For given calibration: @@ -162,7 +161,9 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah, * NF is slow time-variant, so it is OK to use a historical * value. */ - ath9k_hw_loadnf(ah, ah->curchan); + ret = ath9k_hw_loadnf(ah, ah->curchan); + if (ret < 0) + return ret; /* start NF calibration, without updating BB NF register */ ath9k_hw_start_nfcal(ah, false); @@ -176,7 +177,7 @@ static void ar9003_hw_iqcal_collect(struct ath_hw *ah) int i; /* Accumulate IQ cal measures for active chains */ - for (i = 0; i < AR5416_MAX_CHAINS; i++) { + for (i = 0; i < AR9300_MAX_CHAINS; i++) { if (ah->txchainmask & BIT(i)) { ah->totalPowerMeasI[i] += REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); @@ -326,6 +327,224 @@ static void ar9003_hw_init_cal_settings(struct ath_hw *ah) ah->supp_cals = IQ_MISMATCH_CAL; } +#define OFF_UPPER_LT 24 +#define OFF_LOWER_LT 7 + +static bool ar9003_hw_dynamic_osdac_selection(struct ath_hw *ah, + bool txiqcal_done) +{ + struct ath_common *common = ath9k_hw_common(ah); + int ch0_done, osdac_ch0, dc_off_ch0_i1, dc_off_ch0_q1, dc_off_ch0_i2, + dc_off_ch0_q2, dc_off_ch0_i3, dc_off_ch0_q3; + int ch1_done, osdac_ch1, dc_off_ch1_i1, dc_off_ch1_q1, dc_off_ch1_i2, + dc_off_ch1_q2, dc_off_ch1_i3, dc_off_ch1_q3; + int ch2_done, osdac_ch2, dc_off_ch2_i1, dc_off_ch2_q1, dc_off_ch2_i2, + dc_off_ch2_q2, dc_off_ch2_i3, dc_off_ch2_q3; + bool status; + u32 temp, val; + + /* + * Clear offset and IQ calibration, run AGC cal. + */ + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), + AR_PHY_AGC_CONTROL_OFFSET_CAL); + REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), + AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); + REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah), + REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) | AR_PHY_AGC_CONTROL_CAL); + + status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah), + AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT); + if (!status) { + ath_dbg(common, CALIBRATE, + "AGC cal without offset cal failed to complete in 1ms"); + return false; + } + + /* + * Allow only offset calibration and disable the others + * (Carrier Leak calibration, TX Filter calibration and + * Peak Detector offset calibration). + */ + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), + AR_PHY_AGC_CONTROL_OFFSET_CAL); + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, + AR_PHY_CL_CAL_ENABLE); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), + AR_PHY_AGC_CONTROL_FLTR_CAL); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), + AR_PHY_AGC_CONTROL_PKDET_CAL); + + ch0_done = 0; + ch1_done = 0; + ch2_done = 0; + + while ((ch0_done == 0) || (ch1_done == 0) || (ch2_done == 0)) { + osdac_ch0 = (REG_READ(ah, AR_PHY_65NM_CH0_BB1) >> 30) & 0x3; + osdac_ch1 = (REG_READ(ah, AR_PHY_65NM_CH1_BB1) >> 30) & 0x3; + osdac_ch2 = (REG_READ(ah, AR_PHY_65NM_CH2_BB1) >> 30) & 0x3; + + REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah), + REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) | AR_PHY_AGC_CONTROL_CAL); + + status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah), + AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT); + if (!status) { + ath_dbg(common, CALIBRATE, + "DC offset cal failed to complete in 1ms"); + return false; + } + + REG_CLR_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + /* + * High gain. + */ + REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (1 << 8))); + REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (1 << 8))); + REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (1 << 8))); + + temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); + dc_off_ch0_i1 = (temp >> 26) & 0x1f; + dc_off_ch0_q1 = (temp >> 21) & 0x1f; + + temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); + dc_off_ch1_i1 = (temp >> 26) & 0x1f; + dc_off_ch1_q1 = (temp >> 21) & 0x1f; + + temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); + dc_off_ch2_i1 = (temp >> 26) & 0x1f; + dc_off_ch2_q1 = (temp >> 21) & 0x1f; + + /* + * Low gain. + */ + REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (2 << 8))); + REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (2 << 8))); + REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (2 << 8))); + + temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); + dc_off_ch0_i2 = (temp >> 26) & 0x1f; + dc_off_ch0_q2 = (temp >> 21) & 0x1f; + + temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); + dc_off_ch1_i2 = (temp >> 26) & 0x1f; + dc_off_ch1_q2 = (temp >> 21) & 0x1f; + + temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); + dc_off_ch2_i2 = (temp >> 26) & 0x1f; + dc_off_ch2_q2 = (temp >> 21) & 0x1f; + + /* + * Loopback. + */ + REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (3 << 8))); + REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (3 << 8))); + REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (3 << 8))); + + temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); + dc_off_ch0_i3 = (temp >> 26) & 0x1f; + dc_off_ch0_q3 = (temp >> 21) & 0x1f; + + temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); + dc_off_ch1_i3 = (temp >> 26) & 0x1f; + dc_off_ch1_q3 = (temp >> 21) & 0x1f; + + temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); + dc_off_ch2_i3 = (temp >> 26) & 0x1f; + dc_off_ch2_q3 = (temp >> 21) & 0x1f; + + if ((dc_off_ch0_i1 > OFF_UPPER_LT) || (dc_off_ch0_i1 < OFF_LOWER_LT) || + (dc_off_ch0_i2 > OFF_UPPER_LT) || (dc_off_ch0_i2 < OFF_LOWER_LT) || + (dc_off_ch0_i3 > OFF_UPPER_LT) || (dc_off_ch0_i3 < OFF_LOWER_LT) || + (dc_off_ch0_q1 > OFF_UPPER_LT) || (dc_off_ch0_q1 < OFF_LOWER_LT) || + (dc_off_ch0_q2 > OFF_UPPER_LT) || (dc_off_ch0_q2 < OFF_LOWER_LT) || + (dc_off_ch0_q3 > OFF_UPPER_LT) || (dc_off_ch0_q3 < OFF_LOWER_LT)) { + if (osdac_ch0 == 3) { + ch0_done = 1; + } else { + osdac_ch0++; + + val = REG_READ(ah, AR_PHY_65NM_CH0_BB1) & 0x3fffffff; + val |= (osdac_ch0 << 30); + REG_WRITE(ah, AR_PHY_65NM_CH0_BB1, val); + + ch0_done = 0; + } + } else { + ch0_done = 1; + } + + if ((dc_off_ch1_i1 > OFF_UPPER_LT) || (dc_off_ch1_i1 < OFF_LOWER_LT) || + (dc_off_ch1_i2 > OFF_UPPER_LT) || (dc_off_ch1_i2 < OFF_LOWER_LT) || + (dc_off_ch1_i3 > OFF_UPPER_LT) || (dc_off_ch1_i3 < OFF_LOWER_LT) || + (dc_off_ch1_q1 > OFF_UPPER_LT) || (dc_off_ch1_q1 < OFF_LOWER_LT) || + (dc_off_ch1_q2 > OFF_UPPER_LT) || (dc_off_ch1_q2 < OFF_LOWER_LT) || + (dc_off_ch1_q3 > OFF_UPPER_LT) || (dc_off_ch1_q3 < OFF_LOWER_LT)) { + if (osdac_ch1 == 3) { + ch1_done = 1; + } else { + osdac_ch1++; + + val = REG_READ(ah, AR_PHY_65NM_CH1_BB1) & 0x3fffffff; + val |= (osdac_ch1 << 30); + REG_WRITE(ah, AR_PHY_65NM_CH1_BB1, val); + + ch1_done = 0; + } + } else { + ch1_done = 1; + } + + if ((dc_off_ch2_i1 > OFF_UPPER_LT) || (dc_off_ch2_i1 < OFF_LOWER_LT) || + (dc_off_ch2_i2 > OFF_UPPER_LT) || (dc_off_ch2_i2 < OFF_LOWER_LT) || + (dc_off_ch2_i3 > OFF_UPPER_LT) || (dc_off_ch2_i3 < OFF_LOWER_LT) || + (dc_off_ch2_q1 > OFF_UPPER_LT) || (dc_off_ch2_q1 < OFF_LOWER_LT) || + (dc_off_ch2_q2 > OFF_UPPER_LT) || (dc_off_ch2_q2 < OFF_LOWER_LT) || + (dc_off_ch2_q3 > OFF_UPPER_LT) || (dc_off_ch2_q3 < OFF_LOWER_LT)) { + if (osdac_ch2 == 3) { + ch2_done = 1; + } else { + osdac_ch2++; + + val = REG_READ(ah, AR_PHY_65NM_CH2_BB1) & 0x3fffffff; + val |= (osdac_ch2 << 30); + REG_WRITE(ah, AR_PHY_65NM_CH2_BB1, val); + + ch2_done = 0; + } + } else { + ch2_done = 1; + } + } + + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), + AR_PHY_AGC_CONTROL_OFFSET_CAL); + REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + /* + * We don't need to check txiqcal_done here since it is always + * set for AR9550. + */ + REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), + AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); + + return true; +} + /* * solve 4x4 linear equation used in loopback iq cal. */ @@ -347,7 +566,7 @@ static bool ar9003_hw_solve_iq_cal(struct ath_hw *ah, const s32 result_shift = 1 << 15; struct ath_common *common = ath9k_hw_common(ah); - f2 = (f1 * f1 + f3 * f3) / result_shift; + f2 = ((f1 >> 3) * (f1 >> 3) + (f3 >> 3) * (f3 >> 3)) >> 9; if (!f2) { ath_dbg(common, CALIBRATE, "Divide by 0\n"); @@ -437,9 +656,6 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, if (i2_m_q2_a0_d1 > 0x800) i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1); - if (i2_p_q2_a0_d1 > 0x800) - i2_p_q2_a0_d1 = -((0xfff - i2_p_q2_a0_d1) + 1); - if (iq_corr_a0_d1 > 0x800) iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1); @@ -482,6 +698,19 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, return false; } + if ((i2_p_q2_a0_d0 < 1024) || (i2_p_q2_a0_d0 > 2047) || + (i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) || + (i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) || + (i2_p_q2_a0_d0 <= iq_corr_a0_d0) || + (i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) || + (i2_p_q2_a0_d1 <= iq_corr_a0_d1) || + (i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) || + (i2_p_q2_a1_d0 <= iq_corr_a1_d0) || + (i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) || + (i2_p_q2_a1_d1 <= iq_corr_a1_d1)) { + return false; + } + mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0; phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0; @@ -569,7 +798,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, if (q_q_coff > 63) q_q_coff = 63; - iqc_coeff[0] = (q_q_coff * 128) + q_i_coff; + iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff); ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n", chain_idx, iqc_coeff[0]); @@ -600,7 +829,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, if (q_q_coff > 63) q_q_coff = 63; - iqc_coeff[1] = (q_q_coff * 128) + q_i_coff; + iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff); ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n", chain_idx, iqc_coeff[1]); @@ -608,7 +837,8 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, return true; } -static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, +static void ar9003_hw_detect_outlier(int mp_coeff[][MAXIQCAL], + int nmeasurement, int max_delta) { int mp_max = -64, max_idx = 0; @@ -617,20 +847,20 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, /* find min/max mismatch across all calibrated gains */ for (i = 0; i < nmeasurement; i++) { - if (mp_coeff[i] > mp_max) { - mp_max = mp_coeff[i]; + if (mp_coeff[i][0] > mp_max) { + mp_max = mp_coeff[i][0]; max_idx = i; - } else if (mp_coeff[i] < mp_min) { - mp_min = mp_coeff[i]; + } else if (mp_coeff[i][0] < mp_min) { + mp_min = mp_coeff[i][0]; min_idx = i; } } /* find average (exclude max abs value) */ for (i = 0; i < nmeasurement; i++) { - if ((abs(mp_coeff[i]) < abs(mp_max)) || - (abs(mp_coeff[i]) < abs(mp_min))) { - mp_avg += mp_coeff[i]; + if ((abs(mp_coeff[i][0]) < abs(mp_max)) || + (abs(mp_coeff[i][0]) < abs(mp_min))) { + mp_avg += mp_coeff[i][0]; mp_count++; } } @@ -642,7 +872,7 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, if (mp_count) mp_avg /= mp_count; else - mp_avg = mp_coeff[nmeasurement - 1]; + mp_avg = mp_coeff[nmeasurement - 1][0]; /* detect outlier */ if (abs(mp_max - mp_min) > max_delta) { @@ -651,22 +881,23 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, else outlier_idx = min_idx; - mp_coeff[outlier_idx] = mp_avg; + mp_coeff[outlier_idx][0] = mp_avg; } } -static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, - struct coeff *coeff, - bool is_reusable) +static void ar9003_hw_tx_iq_cal_outlier_detection(struct ath_hw *ah, + struct coeff *coeff, + bool is_reusable) { int i, im, nmeasurement; + int magnitude, phase; u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS]; struct ath9k_hw_cal_data *caldata = ah->caldata; memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff)); for (i = 0; i < MAX_MEASUREMENT / 2; i++) { tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] = - AR_PHY_TX_IQCAL_CORR_COEFF_B0(i); + AR_PHY_TX_IQCAL_CORR_COEFF_B0(ah, i); if (!AR_SREV_9485(ah)) { tx_corr_coeff[i * 2][1] = tx_corr_coeff[(i * 2) + 1][1] = @@ -683,27 +914,36 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, if (!(ah->txchainmask & (1 << i))) continue; nmeasurement = REG_READ_FIELD(ah, - AR_PHY_TX_IQCAL_STATUS_B0, + AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0); if (nmeasurement > MAX_MEASUREMENT) nmeasurement = MAX_MEASUREMENT; - /* detect outlier only if nmeasurement > 1 */ - if (nmeasurement > 1) { - /* Detect magnitude outlier */ - ar9003_hw_detect_outlier(coeff->mag_coeff[i], - nmeasurement, MAX_MAG_DELTA); - - /* Detect phase outlier */ - ar9003_hw_detect_outlier(coeff->phs_coeff[i], - nmeasurement, MAX_PHS_DELTA); + /* + * Skip normal outlier detection for AR9550. + */ + if (!AR_SREV_9550(ah)) { + /* detect outlier only if nmeasurement > 1 */ + if (nmeasurement > 1) { + /* Detect magnitude outlier */ + ar9003_hw_detect_outlier(coeff->mag_coeff[i], + nmeasurement, + MAX_MAG_DELTA); + + /* Detect phase outlier */ + ar9003_hw_detect_outlier(coeff->phs_coeff[i], + nmeasurement, + MAX_PHS_DELTA); + } } for (im = 0; im < nmeasurement; im++) { + magnitude = coeff->mag_coeff[i][im][0]; + phase = coeff->phs_coeff[i][im][0]; - coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) | - ((coeff->phs_coeff[i][im] & 0x7f) << 7); + coeff->iqc_coeff[0] = + (phase & 0x7f) | ((magnitude & 0x7f) << 7); if ((im % 2) == 0) REG_RMW_FIELD(ah, tx_corr_coeff[im][i], @@ -727,8 +967,12 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); - if (caldata) - caldata->done_txiqcal_once = is_reusable; + if (caldata) { + if (is_reusable) + set_bit(TXIQCAL_DONE, &caldata->cal_flags); + else + clear_bit(TXIQCAL_DONE, &caldata->cal_flags); + } return; } @@ -744,10 +988,10 @@ static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE, 0); - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, + REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START(ah), AR_PHY_TX_IQCAL_START_DO_CAL, 1); - if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, + if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START(ah), AR_PHY_TX_IQCAL_START_DO_CAL, 0, AH_WAIT_TIMEOUT)) { ath_dbg(common, CALIBRATE, "Tx IQ Cal is not completed\n"); @@ -756,11 +1000,63 @@ static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) return true; } -static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) +static void __ar955x_tx_iq_cal_sort(struct ath_hw *ah, + struct coeff *coeff, + int i, int nmeasurement) +{ + struct ath_common *common = ath9k_hw_common(ah); + int im, ix, iy; + + for (im = 0; im < nmeasurement; im++) { + for (ix = 0; ix < MAXIQCAL - 1; ix++) { + for (iy = ix + 1; iy <= MAXIQCAL - 1; iy++) { + if (coeff->mag_coeff[i][im][iy] < + coeff->mag_coeff[i][im][ix]) { + swap(coeff->mag_coeff[i][im][ix], + coeff->mag_coeff[i][im][iy]); + } + if (coeff->phs_coeff[i][im][iy] < + coeff->phs_coeff[i][im][ix]) { + swap(coeff->phs_coeff[i][im][ix], + coeff->phs_coeff[i][im][iy]); + } + } + } + coeff->mag_coeff[i][im][0] = coeff->mag_coeff[i][im][MAXIQCAL / 2]; + coeff->phs_coeff[i][im][0] = coeff->phs_coeff[i][im][MAXIQCAL / 2]; + + ath_dbg(common, CALIBRATE, + "IQCAL: Median [ch%d][gain%d]: mag = %d phase = %d\n", + i, im, + coeff->mag_coeff[i][im][0], + coeff->phs_coeff[i][im][0]); + } +} + +static bool ar955x_tx_iq_cal_median(struct ath_hw *ah, + struct coeff *coeff, + int iqcal_idx, + int nmeasurement) +{ + int i; + + if ((iqcal_idx + 1) != MAXIQCAL) + return false; + + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + __ar955x_tx_iq_cal_sort(ah, coeff, i, nmeasurement); + } + + return true; +} + +static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, + int iqcal_idx, + bool is_reusable) { struct ath_common *common = ath9k_hw_common(ah); const u32 txiqcal_status[AR9300_MAX_CHAINS] = { - AR_PHY_TX_IQCAL_STATUS_B0, + AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_TX_IQCAL_STATUS_B1, AR_PHY_TX_IQCAL_STATUS_B2, }; @@ -769,17 +1065,18 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) AR_PHY_CHAN_INFO_TAB_1, AR_PHY_CHAN_INFO_TAB_2, }; - struct coeff coeff; + static struct coeff coeff; s32 iq_res[6]; int i, im, j; - int nmeasurement; + int nmeasurement = 0; + bool outlier_detect = true; for (i = 0; i < AR9300_MAX_CHAINS; i++) { if (!(ah->txchainmask & (1 << i))) continue; nmeasurement = REG_READ_FIELD(ah, - AR_PHY_TX_IQCAL_STATUS_B0, + AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0); if (nmeasurement > MAX_MEASUREMENT) nmeasurement = MAX_MEASUREMENT; @@ -799,7 +1096,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) u32 idx = 2 * j, offset = 4 * (3 * im + j); REG_RMW_FIELD(ah, - AR_PHY_CHAN_INFO_MEMORY, + AR_PHY_CHAN_INFO_MEMORY(ah), AR_PHY_CHAN_INFO_TAB_S2_READ, 0); @@ -809,7 +1106,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) offset); REG_RMW_FIELD(ah, - AR_PHY_CHAN_INFO_MEMORY, + AR_PHY_CHAN_INFO_MEMORY(ah), AR_PHY_CHAN_INFO_TAB_S2_READ, 1); @@ -830,17 +1127,23 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) goto tx_iqcal_fail; } - coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f; - coeff.phs_coeff[i][im] = + coeff.phs_coeff[i][im][iqcal_idx] = + coeff.iqc_coeff[0] & 0x7f; + coeff.mag_coeff[i][im][iqcal_idx] = (coeff.iqc_coeff[0] >> 7) & 0x7f; - if (coeff.mag_coeff[i][im] > 63) - coeff.mag_coeff[i][im] -= 128; - if (coeff.phs_coeff[i][im] > 63) - coeff.phs_coeff[i][im] -= 128; + if (coeff.mag_coeff[i][im][iqcal_idx] > 63) + coeff.mag_coeff[i][im][iqcal_idx] -= 128; + if (coeff.phs_coeff[i][im][iqcal_idx] > 63) + coeff.phs_coeff[i][im][iqcal_idx] -= 128; } } - ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable); + + if (AR_SREV_9550(ah)) + outlier_detect = ar955x_tx_iq_cal_median(ah, &coeff, + iqcal_idx, nmeasurement); + if (outlier_detect) + ar9003_hw_tx_iq_cal_outlier_detection(ah, &coeff, is_reusable); return; @@ -858,7 +1161,7 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah) memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff)); for (i = 0; i < MAX_MEASUREMENT / 2; i++) { tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] = - AR_PHY_TX_IQCAL_CORR_COEFF_B0(i); + AR_PHY_TX_IQCAL_CORR_COEFF_B0(ah, i); if (!AR_SREV_9485(ah)) { tx_corr_coeff[i * 2][1] = tx_corr_coeff[(i * 2) + 1][1] = @@ -894,37 +1197,61 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah) static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) { - int offset[8], total = 0, test; - int agc_out, i; + int offset[8] = {0}, total = 0, test; + int agc_out, i, peak_detect_threshold = 0; + + if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) + peak_detect_threshold = 8; + else if (AR_SREV_9561(ah)) + peak_detect_threshold = 11; + /* + * Turn off LNA/SW. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0x1); REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC, 0x0); - if (is_2g) - REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), - AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0); - else - REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), - AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0); + if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9330_11(ah)) { + if (is_2g) + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0); + else + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), + AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0); + } + + /* + * Turn off RXON. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), AR_PHY_65NM_RXTX2_RXON_OVR, 0x1); REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), AR_PHY_65NM_RXTX2_RXON, 0x0); + /* + * Turn on AGC for cal. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1); REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR, 0x1); REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0x1); + + if (AR_SREV_9330_11(ah)) + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0); + if (is_2g) REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), - AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, 0x0); + AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, + peak_detect_threshold); else REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), - AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, 0x0); + AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, + peak_detect_threshold); for (i = 6; i > 0; i--) { offset[i] = BIT(i - 1); @@ -952,20 +1279,31 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g) REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, total); + /* + * Turn on LNA. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain), AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0); + /* + * Turn off RXON. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain), AR_PHY_65NM_RXTX2_RXON_OVR, 0); + /* + * Turn off peak detect calibration. + */ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0); } -static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah, - struct ath9k_channel *chan) +static void ar9003_hw_do_pcoem_manual_peak_cal(struct ath_hw *ah, + struct ath9k_channel *chan, + bool run_rtt_cal) { + struct ath9k_hw_cal_data *caldata = ah->caldata; int i; - if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah) && !AR_SREV_9485(ah)) + if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && !run_rtt_cal) return; for (i = 0; i < AR9300_MAX_CHAINS; i++) { @@ -973,6 +1311,27 @@ static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah, continue; ar9003_hw_manual_peak_cal(ah, i, IS_CHAN_2GHZ(chan)); } + + if (caldata) + set_bit(SW_PKDET_DONE, &caldata->cal_flags); + + if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && caldata) { + if (IS_CHAN_2GHZ(chan)){ + caldata->caldac[0] = REG_READ_FIELD(ah, + AR_PHY_65NM_RXRF_AGC(0), + AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR); + caldata->caldac[1] = REG_READ_FIELD(ah, + AR_PHY_65NM_RXRF_AGC(1), + AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR); + } else { + caldata->caldac[0] = REG_READ_FIELD(ah, + AR_PHY_65NM_RXRF_AGC(0), + AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR); + caldata->caldac[1] = REG_READ_FIELD(ah, + AR_PHY_65NM_RXRF_AGC(1), + AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR); + } + } } static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable) @@ -987,10 +1346,10 @@ static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable) if (!caldata || !(ah->enabled_cals & TX_CL_CAL)) return; - txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & + txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) & AR_PHY_AGC_CONTROL_CLC_SUCCESS); - if (caldata->done_txclcal_once) { + if (test_bit(TXCLCAL_DONE, &caldata->cal_flags)) { for (i = 0; i < AR9300_MAX_CHAINS; i++) { if (!(ah->txchainmask & (1 << i))) continue; @@ -1006,19 +1365,40 @@ static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable) caldata->tx_clcal[i][j] = REG_READ(ah, CL_TAB_ENTRY(cl_idx[i])); } - caldata->done_txclcal_once = true; + set_bit(TXCLCAL_DONE, &caldata->cal_flags); } } -static bool ar9003_hw_init_cal(struct ath_hw *ah, - struct ath9k_channel *chan) +static void ar9003_hw_init_cal_common(struct ath_hw *ah) +{ + struct ath9k_hw_cal_data *caldata = ah->caldata; + + /* Initialize list pointers */ + ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; + + INIT_CAL(&ah->iq_caldata); + INSERT_CAL(ah, &ah->iq_caldata); + + /* Initialize current pointer to first element in list */ + ah->cal_list_curr = ah->cal_list; + + if (ah->cal_list_curr) + ath9k_hw_reset_calibration(ah, ah->cal_list_curr); + + if (caldata) + caldata->CalValid = 0; +} + +static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah, + struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_cal_data *caldata = ah->caldata; bool txiqcal_done = false; bool is_reusable = true, status = true; - bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false; + bool run_rtt_cal = false, run_agc_cal; bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT); + u32 rx_delay = 0; u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL | AR_PHY_AGC_CONTROL_FLTR_CAL | AR_PHY_AGC_CONTROL_PKDET_CAL; @@ -1042,17 +1422,22 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, ar9003_hw_rtt_clear_hist(ah); } - if (rtt && !run_rtt_cal) { - agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL); - agc_supp_cals &= agc_ctrl; - agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL | - AR_PHY_AGC_CONTROL_FLTR_CAL | - AR_PHY_AGC_CONTROL_PKDET_CAL); - REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl); + if (rtt) { + if (!run_rtt_cal) { + agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL(ah)); + agc_supp_cals &= agc_ctrl; + agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL | + AR_PHY_AGC_CONTROL_FLTR_CAL | + AR_PHY_AGC_CONTROL_PKDET_CAL); + REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah), agc_ctrl); + } else { + if (ah->ah_flags & AH_FASTCC) + run_agc_cal = true; + } } if (ah->enabled_cals & TX_CL_CAL) { - if (caldata && caldata->done_txclcal_once) + if (caldata && test_bit(TXCLCAL_DONE, &caldata->cal_flags)) REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); else { @@ -1067,7 +1452,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, goto skip_tx_iqcal; /* Do Tx IQ Calibration */ - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, + REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1(ah), AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT); @@ -1076,41 +1461,45 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, * AGC calibration */ if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) { - if (caldata && !caldata->done_txiqcal_once) - REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, + if (caldata && !test_bit(TXIQCAL_DONE, &caldata->cal_flags)) + REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); else - REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, + REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); txiqcal_done = run_agc_cal = true; - } else if (caldata && !caldata->done_txiqcal_once) { - run_agc_cal = true; - sep_iq_cal = true; } skip_tx_iqcal: if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal) ar9003_mci_init_cal_req(ah, &is_reusable); - if (sep_iq_cal) { - txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); + if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) { + rx_delay = REG_READ(ah, AR_PHY_RX_DELAY); + /* Disable BB_active */ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); udelay(5); + REG_WRITE(ah, AR_PHY_RX_DELAY, AR_PHY_RX_DELAY_DELAY); REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); } if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { /* Calibrate the AGC */ - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | + REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah), + REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) | AR_PHY_AGC_CONTROL_CAL); /* Poll for offset calibration complete */ - status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT); - ar9003_hw_do_manual_peak_cal(ah, chan); + ar9003_hw_do_pcoem_manual_peak_cal(ah, chan, run_rtt_cal); + } + + if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) { + REG_WRITE(ah, AR_PHY_RX_DELAY, rx_delay); + udelay(5); } if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal) @@ -1118,7 +1507,7 @@ skip_tx_iqcal: if (rtt && !run_rtt_cal) { agc_ctrl |= agc_supp_cals; - REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl); + REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah), agc_ctrl); } if (!status) { @@ -1132,20 +1521,24 @@ skip_tx_iqcal: } if (txiqcal_done) - ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable); - else if (caldata && caldata->done_txiqcal_once) + ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable); + else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags)) ar9003_hw_tx_iq_cal_reload(ah); ar9003_hw_cl_cal_post_proc(ah, is_reusable); if (run_rtt_cal && caldata) { if (is_reusable) { - if (!ath9k_hw_rfbus_req(ah)) + if (!ath9k_hw_rfbus_req(ah)) { ath_err(ath9k_hw_common(ah), "Could not stop baseband\n"); - else + } else { ar9003_hw_rtt_fill_hist(ah); + if (test_bit(SW_PKDET_DONE, &caldata->cal_flags)) + ar9003_hw_rtt_load_hist(ah); + } + ath9k_hw_rfbus_done(ah); } @@ -1155,21 +1548,135 @@ skip_tx_iqcal: /* Revert chainmask to runtime parameters */ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); - /* Initialize list pointers */ - ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; + ar9003_hw_init_cal_common(ah); - INIT_CAL(&ah->iq_caldata); - INSERT_CAL(ah, &ah->iq_caldata); - ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); + return true; +} - /* Initialize current pointer to first element in list */ - ah->cal_list_curr = ah->cal_list; +static bool do_ar9003_agc_cal(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + bool status; - if (ah->cal_list_curr) - ath9k_hw_reset_calibration(ah, ah->cal_list_curr); + REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah), + REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) | + AR_PHY_AGC_CONTROL_CAL); - if (caldata) - caldata->CalValid = 0; + status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah), + AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT); + if (!status) { + ath_dbg(common, CALIBRATE, + "offset calibration failed to complete in %d ms," + "noisy environment?\n", + AH_WAIT_TIMEOUT / 1000); + return false; + } + + return true; +} + +static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + bool txiqcal_done = false; + bool status = true; + bool run_agc_cal = false, sep_iq_cal = false; + int i = 0; + + /* Use chip chainmask only for calibration */ + ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); + + if (ah->enabled_cals & TX_CL_CAL) { + REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); + run_agc_cal = true; + } + + if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) + goto skip_tx_iqcal; + + /* Do Tx IQ Calibration */ + REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1(ah), + AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, + DELPT); + + /* + * For AR9485 or later chips, TxIQ cal runs as part of + * AGC calibration. Specifically, AR9550 in SoC chips. + */ + if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) { + if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), + AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) { + txiqcal_done = true; + } else { + txiqcal_done = false; + } + run_agc_cal = true; + } else { + sep_iq_cal = true; + run_agc_cal = true; + } + + /* + * In the SoC family, this will run for AR9300, AR9331 and AR9340. + */ + if (sep_iq_cal) { + txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); + udelay(5); + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + } + + if (AR_SREV_9550(ah) && IS_CHAN_2GHZ(chan)) { + if (!ar9003_hw_dynamic_osdac_selection(ah, txiqcal_done)) + return false; + } + +skip_tx_iqcal: + if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->rxchainmask & (1 << i))) + continue; + + ar9003_hw_manual_peak_cal(ah, i, + IS_CHAN_2GHZ(chan)); + } + + /* + * For non-AR9550 chips, we just trigger AGC calibration + * in the HW, poll for completion and then process + * the results. + * + * For AR955x, we run it multiple times and use + * median IQ correction. + */ + if (!AR_SREV_9550(ah)) { + status = do_ar9003_agc_cal(ah); + if (!status) + return false; + + if (txiqcal_done) + ar9003_hw_tx_iq_cal_post_proc(ah, 0, false); + } else { + if (!txiqcal_done) { + status = do_ar9003_agc_cal(ah); + if (!status) + return false; + } else { + for (i = 0; i < MAXIQCAL; i++) { + status = do_ar9003_agc_cal(ah); + if (!status) + return false; + ar9003_hw_tx_iq_cal_post_proc(ah, i, false); + } + } + } + } + + /* Revert chainmask to runtime parameters */ + ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); + + ar9003_hw_init_cal_common(ah); return true; } @@ -1179,8 +1686,12 @@ void ar9003_hw_attach_calib_ops(struct ath_hw *ah) struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); struct ath_hw_ops *ops = ath9k_hw_ops(ah); + if (AR_SREV_9003_PCOEM(ah)) + priv_ops->init_cal = ar9003_hw_init_cal_pcoem; + else + priv_ops->init_cal = ar9003_hw_init_cal_soc; + priv_ops->init_cal_settings = ar9003_hw_init_cal_settings; - priv_ops->init_cal = ar9003_hw_init_cal; priv_ops->setup_calibration = ar9003_hw_setup_calibration; ops->calibrate = ar9003_hw_calibrate; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index d105e43d22e1..73c38a6b4880 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -14,7 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <asm/unaligned.h> +#include <linux/unaligned.h> +#include <linux/kernel.h> #include "hw.h" #include "ar9003_phy.h" #include "ar9003_eeprom.h" @@ -23,8 +24,8 @@ #define COMP_HDR_LEN 4 #define COMP_CKSUM_LEN 2 -#define LE16(x) __constant_cpu_to_le16(x) -#define LE32(x) __constant_cpu_to_le32(x) +#define LE16(x) cpu_to_le16(x) +#define LE32(x) cpu_to_le32(x) /* Local defines to distinguish between extension and control CTL's */ #define EXT_ADDITIVE (0x8000) @@ -53,7 +54,7 @@ static const struct ar9300_eeprom ar9300_default = { .txrxMask = 0x77, /* 4 bits tx and 4 bits rx */ .opCapFlags = { .opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A, - .eepMisc = 0, + .eepMisc = AR9300_EEPMISC_LITTLE_ENDIAN, }, .rfSilent = 0, .blueToothOptions = 0, @@ -131,6 +132,7 @@ static const struct ar9300_eeprom ar9300_default = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), + .switchcomspdt = 0, .xlna_bias_strength = 0, .futureModal = { 0, 0, 0, 0, 0, 0, 0, @@ -138,7 +140,7 @@ static const struct ar9300_eeprom ar9300_default = { }, .base_ext1 = { .ant_div_control = 0, - .future = {0, 0, 0}, + .future = {0, 0}, .tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0} }, .calFreqPier2G = { @@ -333,6 +335,7 @@ static const struct ar9300_eeprom ar9300_default = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0c80c080), .papdRateMaskHt40 = LE32(0x0080c080), + .switchcomspdt = 0, .xlna_bias_strength = 0, .futureModal = { 0, 0, 0, 0, 0, 0, 0, @@ -629,7 +632,7 @@ static const struct ar9300_eeprom ar9300_x113 = { .txrxMask = 0x77, /* 4 bits tx and 4 bits rx */ .opCapFlags = { .opFlags = AR5416_OPFLAGS_11A, - .eepMisc = 0, + .eepMisc = AR9300_EEPMISC_LITTLE_ENDIAN, }, .rfSilent = 0, .blueToothOptions = 0, @@ -707,6 +710,7 @@ static const struct ar9300_eeprom ar9300_x113 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0c80c080), .papdRateMaskHt40 = LE32(0x0080c080), + .switchcomspdt = 0, .xlna_bias_strength = 0, .futureModal = { 0, 0, 0, 0, 0, 0, 0, @@ -714,7 +718,7 @@ static const struct ar9300_eeprom ar9300_x113 = { }, .base_ext1 = { .ant_div_control = 0, - .future = {0, 0, 0}, + .future = {0, 0}, .tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0} }, .calFreqPier2G = { @@ -909,6 +913,7 @@ static const struct ar9300_eeprom ar9300_x113 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), + .switchcomspdt = 0, .xlna_bias_strength = 0, .futureModal = { 0, 0, 0, 0, 0, 0, 0, @@ -1206,7 +1211,7 @@ static const struct ar9300_eeprom ar9300_h112 = { .txrxMask = 0x77, /* 4 bits tx and 4 bits rx */ .opCapFlags = { .opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A, - .eepMisc = 0, + .eepMisc = AR9300_EEPMISC_LITTLE_ENDIAN, }, .rfSilent = 0, .blueToothOptions = 0, @@ -1284,6 +1289,7 @@ static const struct ar9300_eeprom ar9300_h112 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0c80c080), .papdRateMaskHt40 = LE32(0x0080c080), + .switchcomspdt = 0, .xlna_bias_strength = 0, .futureModal = { 0, 0, 0, 0, 0, 0, 0, @@ -1291,7 +1297,7 @@ static const struct ar9300_eeprom ar9300_h112 = { }, .base_ext1 = { .ant_div_control = 0, - .future = {0, 0, 0}, + .future = {0, 0}, .tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0} }, .calFreqPier2G = { @@ -1486,6 +1492,7 @@ static const struct ar9300_eeprom ar9300_h112 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), + .switchcomspdt = 0, .xlna_bias_strength = 0, .futureModal = { 0, 0, 0, 0, 0, 0, 0, @@ -1783,7 +1790,7 @@ static const struct ar9300_eeprom ar9300_x112 = { .txrxMask = 0x77, /* 4 bits tx and 4 bits rx */ .opCapFlags = { .opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A, - .eepMisc = 0, + .eepMisc = AR9300_EEPMISC_LITTLE_ENDIAN, }, .rfSilent = 0, .blueToothOptions = 0, @@ -1861,6 +1868,7 @@ static const struct ar9300_eeprom ar9300_x112 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0c80c080), .papdRateMaskHt40 = LE32(0x0080c080), + .switchcomspdt = 0, .xlna_bias_strength = 0, .futureModal = { 0, 0, 0, 0, 0, 0, 0, @@ -1868,7 +1876,7 @@ static const struct ar9300_eeprom ar9300_x112 = { }, .base_ext1 = { .ant_div_control = 0, - .future = {0, 0, 0}, + .future = {0, 0}, .tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0} }, .calFreqPier2G = { @@ -2063,6 +2071,7 @@ static const struct ar9300_eeprom ar9300_x112 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), + .switchcomspdt = 0, .xlna_bias_strength = 0, .futureModal = { 0, 0, 0, 0, 0, 0, 0, @@ -2359,7 +2368,7 @@ static const struct ar9300_eeprom ar9300_h116 = { .txrxMask = 0x33, /* 4 bits tx and 4 bits rx */ .opCapFlags = { .opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A, - .eepMisc = 0, + .eepMisc = AR9300_EEPMISC_LITTLE_ENDIAN, }, .rfSilent = 0, .blueToothOptions = 0, @@ -2437,6 +2446,7 @@ static const struct ar9300_eeprom ar9300_h116 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0c80C080), .papdRateMaskHt40 = LE32(0x0080C080), + .switchcomspdt = 0, .xlna_bias_strength = 0, .futureModal = { 0, 0, 0, 0, 0, 0, 0, @@ -2444,7 +2454,7 @@ static const struct ar9300_eeprom ar9300_h116 = { }, .base_ext1 = { .ant_div_control = 0, - .future = {0, 0, 0}, + .future = {0, 0}, .tempslopextension = {0, 0, 0, 0, 0, 0, 0, 0} }, .calFreqPier2G = { @@ -2639,6 +2649,7 @@ static const struct ar9300_eeprom ar9300_h116 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), + .switchcomspdt = 0, .xlna_bias_strength = 0, .futureModal = { 0, 0, 0, 0, 0, 0, 0, @@ -2936,14 +2947,12 @@ static const struct ar9300_eeprom *ar9300_eep_templates[] = { static const struct ar9300_eeprom *ar9003_eeprom_struct_find_by_id(int id) { -#define N_LOOP (sizeof(ar9300_eep_templates) / sizeof(ar9300_eep_templates[0])) int it; - for (it = 0; it < N_LOOP; it++) + for (it = 0; it < ARRAY_SIZE(ar9300_eep_templates); it++) if (ar9300_eep_templates[it]->templateVersion == id) return ar9300_eep_templates[it]; return NULL; -#undef N_LOOP } static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah) @@ -2991,7 +3000,10 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah, case EEP_CHAIN_MASK_REDUCE: return (pBase->miscConfiguration >> 0x3) & 0x1; case EEP_ANT_DIV_CTL1: - return eep->base_ext1.ant_div_control; + if (AR_SREV_9565(ah)) + return AR9300_EEP_ANTDIV_CONTROL_DEFAULT_VALUE; + else + return eep->base_ext1.ant_div_control; case EEP_ANTENNA_GAIN_5G: return eep->modalHeader5G.antennaGain; case EEP_ANTENNA_GAIN_2G: @@ -3072,13 +3084,13 @@ error: static bool ar9300_otp_read_word(struct ath_hw *ah, int addr, u32 *data) { - REG_READ(ah, AR9300_OTP_BASE + (4 * addr)); + REG_READ(ah, AR9300_OTP_BASE(ah) + (4 * addr)); - if (!ath9k_hw_wait(ah, AR9300_OTP_STATUS, AR9300_OTP_STATUS_TYPE, + if (!ath9k_hw_wait(ah, AR9300_OTP_STATUS(ah), AR9300_OTP_STATUS_TYPE, AR9300_OTP_STATUS_VALID, 1000)) return false; - *data = REG_READ(ah, AR9300_OTP_READ_DATA); + *data = REG_READ(ah, AR9300_OTP_READ_DATA(ah)); return true; } @@ -3189,8 +3201,7 @@ static int ar9300_compress_decision(struct ath_hw *ah, it, length); break; case _CompressBlock: - if (reference == 0) { - } else { + if (reference != 0) { eep = ar9003_eeprom_struct_find_by_id(reference); if (eep == NULL) { ath_dbg(common, EEPROM, @@ -3240,7 +3251,8 @@ static int ar9300_eeprom_restore_flash(struct ath_hw *ah, u8 *mptr, int i; for (i = 0; i < mdata_size / 2; i++, data++) - ath9k_hw_nvram_read(ah, i, data); + if (!ath9k_hw_nvram_read(ah, i, data)) + return -EIO; return 0; } @@ -3270,7 +3282,8 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, if (ath9k_hw_use_flash(ah)) { u8 txrx; - ar9300_eeprom_restore_flash(ah, mptr, mdata_size); + if (ar9300_eeprom_restore_flash(ah, mptr, mdata_size)) + return -EIO; /* check if eeprom contains valid data */ eep = (struct ar9300_eeprom *) mptr; @@ -3297,6 +3310,12 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, if (ar9300_check_eeprom_header(ah, read, cptr)) goto found; + cptr = AR9300_BASE_ADDR_4K; + ath_dbg(common, EEPROM, "Trying EEPROM access at Address 0x%04x\n", + cptr); + if (ar9300_check_eeprom_header(ah, read, cptr)) + goto found; + cptr = AR9300_BASE_ADDR_512; ath_dbg(common, EEPROM, "Trying EEPROM access at Address 0x%04x\n", cptr); @@ -3332,7 +3351,8 @@ found: "Found block at %x: code=%d ref=%d length=%d major=%d minor=%d\n", cptr, code, reference, length, major, minor); if ((!AR_SREV_9485(ah) && length >= 1024) || - (AR_SREV_9485(ah) && length > EEPROM_DATA_LEN_9485)) { + (AR_SREV_9485(ah) && length > EEPROM_DATA_LEN_9485) || + (length > cptr)) { ath_dbg(common, EEPROM, "Skipping bad header\n"); cptr -= COMP_HDR_LEN; continue; @@ -3417,6 +3437,60 @@ static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size, return len; } +static u32 ar9003_dump_cal_data(struct ath_hw *ah, char *buf, u32 len, u32 size, + bool is_2g) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + struct ar9300_base_eep_hdr *pBase; + struct ar9300_cal_data_per_freq_op_loop *cal_pier; + int cal_pier_nr; + int freq; + int i, j; + + pBase = &eep->baseEepHeader; + + if (is_2g) + cal_pier_nr = AR9300_NUM_2G_CAL_PIERS; + else + cal_pier_nr = AR9300_NUM_5G_CAL_PIERS; + + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!((pBase->txrxMask >> i) & 1)) + continue; + + len += scnprintf(buf + len, size - len, "Chain %d\n", i); + + len += scnprintf(buf + len, size - len, + "Freq\t ref\tvolt\ttemp\tnf_cal\tnf_pow\trx_temp\n"); + + for (j = 0; j < cal_pier_nr; j++) { + if (is_2g) { + cal_pier = &eep->calPierData2G[i][j]; + freq = 2300 + eep->calFreqPier2G[j]; + } else { + cal_pier = &eep->calPierData5G[i][j]; + freq = 4800 + eep->calFreqPier5G[j] * 5; + } + + len += scnprintf(buf + len, size - len, + "%d\t", freq); + + len += scnprintf(buf + len, size - len, + "%d\t%d\t%d\t%d\t%d\t%d\n", + cal_pier->refPower, + cal_pier->voltMeas, + cal_pier->tempMeas, + cal_pier->rxTempMeas ? + N2DBM(cal_pier->rxNoisefloorCal) : 0, + cal_pier->rxTempMeas ? + N2DBM(cal_pier->rxNoisefloorPower) : 0, + cal_pier->rxTempMeas); + } + } + + return len; +} + static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, u8 *buf, u32 len, u32 size) { @@ -3424,14 +3498,22 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, struct ar9300_base_eep_hdr *pBase; if (!dump_base_hdr) { - len += snprintf(buf + len, size - len, - "%20s :\n", "2GHz modal Header"); + len += scnprintf(buf + len, size - len, + "%20s :\n", "2GHz modal Header"); len = ar9003_dump_modal_eeprom(buf, len, size, &eep->modalHeader2G); - len += snprintf(buf + len, size - len, - "%20s :\n", "5GHz modal Header"); + + len += scnprintf(buf + len, size - len, "Calibration data\n"); + len = ar9003_dump_cal_data(ah, buf, len, size, true); + + len += scnprintf(buf + len, size - len, + "%20s :\n", "5GHz modal Header"); len = ar9003_dump_modal_eeprom(buf, len, size, &eep->modalHeader5G); + + len += scnprintf(buf + len, size - len, "Calibration data\n"); + len = ar9003_dump_cal_data(ah, buf, len, size, false); + goto out; } @@ -3454,7 +3536,8 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, AR5416_OPFLAGS_N_5G_HT20)); PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags.opFlags & AR5416_OPFLAGS_N_5G_HT40)); - PR_EEP("Big Endian", !!(pBase->opCapFlags.eepMisc & 0x01)); + PR_EEP("Big Endian", !!(pBase->opCapFlags.eepMisc & + AR5416_EEPMISC_BIG_ENDIAN)); PR_EEP("RF Silent", pBase->rfSilent); PR_EEP("BT option", pBase->blueToothOptions); PR_EEP("Device Cap", pBase->deviceCap); @@ -3479,8 +3562,8 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, PR_EEP("Rx Gain", pBase->txrxgain & 0xf); PR_EEP("SW Reg", le32_to_cpu(pBase->swreg)); - len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", - ah->eeprom.ar9300_eep.macAddr); + len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", + ah->eeprom.ar9300_eep.macAddr); out: if (len > size) len = size; @@ -3522,16 +3605,17 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) { int bias = ar9003_modal_header(ah, is2ghz)->xpaBiasLvl; - if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) - REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); + if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah) || + AR_SREV_9531(ah) || AR_SREV_9561(ah)) + REG_RMW_FIELD(ah, AR_CH0_TOP2(ah), AR_CH0_TOP2_XPABIASLVL, bias); else if (AR_SREV_9462(ah) || AR_SREV_9550(ah) || AR_SREV_9565(ah)) - REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); + REG_RMW_FIELD(ah, AR_CH0_TOP(ah), AR_CH0_TOP_XPABIASLVL, bias); else { - REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); - REG_RMW_FIELD(ah, AR_CH0_THERM, + REG_RMW_FIELD(ah, AR_CH0_TOP(ah), AR_CH0_TOP_XPABIASLVL, bias); + REG_RMW_FIELD(ah, AR_CH0_THERM(ah), AR_CH0_THERM_XPABIASLVL_MSB, bias >> 2); - REG_RMW_FIELD(ah, AR_CH0_THERM, + REG_RMW_FIELD(ah, AR_CH0_THERM(ah), AR_CH0_THERM_XPASHORT2GND, 1); } } @@ -3541,13 +3625,12 @@ static u16 ar9003_switch_com_spdt_get(struct ath_hw *ah, bool is2ghz) return le16_to_cpu(ar9003_modal_header(ah, is2ghz)->switchcomspdt); } - -static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz) +u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz) { return le32_to_cpu(ar9003_modal_header(ah, is2ghz)->antCtrlCommon); } -static u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz) +u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz) { return le32_to_cpu(ar9003_modal_header(ah, is2ghz)->antCtrlCommon2); } @@ -3561,6 +3644,7 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah, int chain, static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) { + struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_capabilities *pCap = &ah->caps; int chain; u32 regval, value, gpio; @@ -3576,8 +3660,8 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) else gpio = AR9300_EXT_LNA_CTL_GPIO_AR9485; - ath9k_hw_cfg_output(ah, gpio, - AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED); + ath9k_hw_gpio_request_out(ah, gpio, NULL, + AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED); } value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz); @@ -3585,7 +3669,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_AR9462_ALL, value); - } else if (AR_SREV_9550(ah)) { + } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) { REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_AR9550_ALL, value); } else @@ -3614,6 +3698,11 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) } value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz); + if (AR_SREV_9485(ah) && common->bt_ant_diversity) { + value &= ~AR_SWITCH_TABLE_COM2_ALL; + value |= ah->config.ant_ctrl_comm2g_switch_enable; + + } REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); if ((AR_SREV_9462(ah)) && (ah->rxchainmask == 0x2)) { @@ -3645,21 +3734,43 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) regval &= (~AR_PHY_ANT_DIV_LNADIV); regval |= ((value >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S; + if (AR_SREV_9485(ah) && common->bt_ant_diversity) + regval |= AR_ANT_DIV_ENABLE; + if (AR_SREV_9565(ah)) { - if (ah->shared_chain_lnadiv) { + if (common->bt_ant_diversity) { regval |= (1 << AR_PHY_ANT_SW_RX_PROT_S); + + REG_SET_BIT(ah, AR_PHY_RESTART, + AR_PHY_RESTART_ENABLE_DIV_M2FLAG); + + /* Force WLAN LNA diversity ON */ + REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, + AR_BTCOEX_WL_LNADIV_FORCE_ON); } else { regval &= ~(1 << AR_PHY_ANT_DIV_LNADIV_S); regval &= ~(1 << AR_PHY_ANT_SW_RX_PROT_S); + + REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, + (1 << AR_PHY_ANT_SW_RX_PROT_S)); + + /* Force WLAN LNA diversity OFF */ + REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV, + AR_BTCOEX_WL_LNADIV_FORCE_ON); } } REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); - /*enable fast_div */ + /* enable fast_div */ regval = REG_READ(ah, AR_PHY_CCK_DETECT); regval &= (~AR_FAST_DIV_ENABLE); regval |= ((value >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S; + + if ((AR_SREV_9485(ah) || AR_SREV_9565(ah)) + && common->bt_ant_diversity) + regval |= AR_FAST_DIV_ENABLE; + REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { @@ -3673,9 +3784,9 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) AR_PHY_ANT_DIV_ALT_GAINTB | AR_PHY_ANT_DIV_MAIN_GAINTB)); /* by default use LNA1 for the main antenna */ - regval |= (AR_PHY_ANT_DIV_LNA1 << + regval |= (ATH_ANT_DIV_COMB_LNA1 << AR_PHY_ANT_DIV_MAIN_LNACONF_S); - regval |= (AR_PHY_ANT_DIV_LNA2 << + regval |= (ATH_ANT_DIV_COMB_LNA2 << AR_PHY_ANT_DIV_ALT_LNACONF_S); REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); } @@ -3800,7 +3911,7 @@ static void ar9003_hw_atten_apply(struct ath_hw *ah, struct ath9k_channel *chan) } /* Test value. if 0 then attenuation is unused. Don't load anything. */ - for (i = 0; i < 3; i++) { + for (i = 0; i < AR9300_MAX_CHAINS; i++) { if (ah->txchainmask & BIT(i)) { value = ar9003_hw_atten_chain_get(ah, i, chan); REG_RMW_FIELD(ah, ext_atten_reg[i], @@ -3813,6 +3924,11 @@ static void ar9003_hw_atten_apply(struct ath_hw *ah, struct ath9k_channel *chan) else value = ar9003_hw_atten_chain_get_margin(ah, i, chan); + if (ah->config.alt_mingainidx) + REG_RMW_FIELD(ah, AR_PHY_EXT_ATTEN_CTL_0, + AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, + value); + REG_RMW_FIELD(ah, ext_atten_reg[i], AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value); @@ -3844,9 +3960,9 @@ void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) if (AR_SREV_9330(ah) || AR_SREV_9485(ah)) { int reg_pmu_set; - reg_pmu_set = REG_READ(ah, AR_PHY_PMU2) & ~AR_PHY_PMU2_PGM; - REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set); - if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set)) + reg_pmu_set = REG_READ(ah, AR_PHY_PMU2(ah)) & ~AR_PHY_PMU2_PGM; + REG_WRITE(ah, AR_PHY_PMU2(ah), reg_pmu_set); + if (!is_pmu_set(ah, AR_PHY_PMU2(ah), reg_pmu_set)) return; if (AR_SREV_9330(ah)) { @@ -3868,24 +3984,28 @@ void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) (3 << 24) | (1 << 28); } - REG_WRITE(ah, AR_PHY_PMU1, reg_pmu_set); - if (!is_pmu_set(ah, AR_PHY_PMU1, reg_pmu_set)) + REG_WRITE(ah, AR_PHY_PMU1(ah), reg_pmu_set); + if (!is_pmu_set(ah, AR_PHY_PMU1(ah), reg_pmu_set)) return; - reg_pmu_set = (REG_READ(ah, AR_PHY_PMU2) & ~0xFFC00000) + reg_pmu_set = (REG_READ(ah, AR_PHY_PMU2(ah)) & ~0xFFC00000) | (4 << 26); - REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set); - if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set)) + REG_WRITE(ah, AR_PHY_PMU2(ah), reg_pmu_set); + if (!is_pmu_set(ah, AR_PHY_PMU2(ah), reg_pmu_set)) return; - reg_pmu_set = (REG_READ(ah, AR_PHY_PMU2) & ~0x00200000) + reg_pmu_set = (REG_READ(ah, AR_PHY_PMU2(ah)) & ~0x00200000) | (1 << 21); - REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set); - if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set)) + REG_WRITE(ah, AR_PHY_PMU2(ah), reg_pmu_set); + if (!is_pmu_set(ah, AR_PHY_PMU2(ah), reg_pmu_set)) return; - } else if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { + } else if (AR_SREV_9462(ah) || AR_SREV_9565(ah) || + AR_SREV_9561(ah)) { reg_val = le32_to_cpu(pBase->swreg); - REG_WRITE(ah, AR_PHY_PMU1, reg_val); + REG_WRITE(ah, AR_PHY_PMU1(ah), reg_val); + + if (AR_SREV_9561(ah)) + REG_WRITE(ah, AR_PHY_PMU2(ah), 0x10200000); } else { /* Internal regulator is ON. Write swreg register. */ reg_val = le32_to_cpu(pBase->swreg); @@ -3901,25 +4021,25 @@ void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) } } else { if (AR_SREV_9330(ah) || AR_SREV_9485(ah)) { - REG_RMW_FIELD(ah, AR_PHY_PMU2, AR_PHY_PMU2_PGM, 0); - while (REG_READ_FIELD(ah, AR_PHY_PMU2, + REG_RMW_FIELD(ah, AR_PHY_PMU2(ah), AR_PHY_PMU2_PGM, 0); + while (REG_READ_FIELD(ah, AR_PHY_PMU2(ah), AR_PHY_PMU2_PGM)) udelay(10); - REG_RMW_FIELD(ah, AR_PHY_PMU1, AR_PHY_PMU1_PWD, 0x1); - while (!REG_READ_FIELD(ah, AR_PHY_PMU1, + REG_RMW_FIELD(ah, AR_PHY_PMU1(ah), AR_PHY_PMU1_PWD, 0x1); + while (!REG_READ_FIELD(ah, AR_PHY_PMU1(ah), AR_PHY_PMU1_PWD)) udelay(10); - REG_RMW_FIELD(ah, AR_PHY_PMU2, AR_PHY_PMU2_PGM, 0x1); - while (!REG_READ_FIELD(ah, AR_PHY_PMU2, + REG_RMW_FIELD(ah, AR_PHY_PMU2(ah), AR_PHY_PMU2_PGM, 0x1); + while (!REG_READ_FIELD(ah, AR_PHY_PMU2(ah), AR_PHY_PMU2_PGM)) udelay(10); } else if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) - REG_RMW_FIELD(ah, AR_PHY_PMU1, AR_PHY_PMU1_PWD, 0x1); + REG_RMW_FIELD(ah, AR_PHY_PMU1(ah), AR_PHY_PMU1_PWD, 0x1); else { - reg_val = REG_READ(ah, AR_RTC_SLEEP_CLK) | + reg_val = REG_READ(ah, AR_RTC_SLEEP_CLK(ah)) | AR_RTC_FORCE_SWREG_PRD; - REG_WRITE(ah, AR_RTC_SLEEP_CLK, reg_val); + REG_WRITE(ah, AR_RTC_SLEEP_CLK(ah), reg_val); } } @@ -3930,14 +4050,14 @@ static void ar9003_hw_apply_tuning_caps(struct ath_hw *ah) struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; u8 tuning_caps_param = eep->baseEepHeader.params_for_tuning_caps[0]; - if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9531(ah)) return; if (eep->baseEepHeader.featureEnable & 0x40) { tuning_caps_param &= 0x7f; - REG_RMW_FIELD(ah, AR_CH0_XTAL, AR_CH0_XTAL_CAPINDAC, + REG_RMW_FIELD(ah, AR_CH0_XTAL(ah), AR_CH0_XTAL_CAPINDAC, tuning_caps_param); - REG_RMW_FIELD(ah, AR_CH0_XTAL, AR_CH0_XTAL_CAPOUTDAC, + REG_RMW_FIELD(ah, AR_CH0_XTAL(ah), AR_CH0_XTAL_CAPOUTDAC, tuning_caps_param); } } @@ -3949,18 +4069,20 @@ static void ar9003_hw_quick_drop_apply(struct ath_hw *ah, u16 freq) int quick_drop; s32 t[3], f[3] = {5180, 5500, 5785}; - if (!(pBase->miscConfiguration & BIT(1))) + if (!(pBase->miscConfiguration & BIT(4))) return; - if (freq < 4000) - quick_drop = eep->modalHeader2G.quick_drop; - else { - t[0] = eep->base_ext1.quick_drop_low; - t[1] = eep->modalHeader5G.quick_drop; - t[2] = eep->base_ext1.quick_drop_high; - quick_drop = ar9003_hw_power_interpolate(freq, f, t, 3); + if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9340(ah)) { + if (freq < 4000) { + quick_drop = eep->modalHeader2G.quick_drop; + } else { + t[0] = eep->base_ext1.quick_drop_low; + t[1] = eep->modalHeader5G.quick_drop; + t[2] = eep->base_ext1.quick_drop_high; + quick_drop = ar9003_hw_power_interpolate(freq, f, t, 3); + } + REG_RMW_FIELD(ah, AR_PHY_AGC, AR_PHY_AGC_QUICK_DROP, quick_drop); } - REG_RMW_FIELD(ah, AR_PHY_AGC, AR_PHY_AGC_QUICK_DROP, quick_drop); } static void ar9003_hw_txend_to_xpa_off_apply(struct ath_hw *ah, bool is2ghz) @@ -3983,7 +4105,11 @@ static void ar9003_hw_xpa_timing_control_apply(struct ath_hw *ah, bool is2ghz) if (!(eep->baseEepHeader.featureEnable & 0x80)) return; - if (!AR_SREV_9300(ah) && !AR_SREV_9340(ah) && !AR_SREV_9580(ah)) + if (!AR_SREV_9300(ah) && + !AR_SREV_9340(ah) && + !AR_SREV_9580(ah) && + !AR_SREV_9531(ah) && + !AR_SREV_9561(ah)) return; xpa_ctl = ar9003_modal_header(ah, is2ghz)->txFrameToXpaOn; @@ -4000,7 +4126,7 @@ static void ar9003_hw_xlna_bias_strength_apply(struct ath_hw *ah, bool is2ghz) struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; u8 bias; - if (!(eep->baseEepHeader.featureEnable & 0x40)) + if (!(eep->baseEepHeader.miscConfiguration & 0x40)) return; if (!AR_SREV_9300(ah)) @@ -4028,28 +4154,29 @@ static int ar9003_hw_get_thermometer(struct ath_hw *ah) static void ar9003_hw_thermometer_apply(struct ath_hw *ah) { + struct ath9k_hw_capabilities *pCap = &ah->caps; int thermometer = ar9003_hw_get_thermometer(ah); u8 therm_on = (thermometer < 0) ? 0 : 1; REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, therm_on); - if (ah->caps.tx_chainmask & BIT(1)) + if (pCap->chip_chainmask & BIT(1)) REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, therm_on); - if (ah->caps.tx_chainmask & BIT(2)) + if (pCap->chip_chainmask & BIT(2)) REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, therm_on); - therm_on = (thermometer < 0) ? 0 : (thermometer == 0); + therm_on = thermometer == 0; REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on); - if (ah->caps.tx_chainmask & BIT(1)) { - therm_on = (thermometer < 0) ? 0 : (thermometer == 1); + if (pCap->chip_chainmask & BIT(1)) { + therm_on = thermometer == 1; REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on); } - if (ah->caps.tx_chainmask & BIT(2)) { - therm_on = (thermometer < 0) ? 0 : (thermometer == 2); + if (pCap->chip_chainmask & BIT(2)) { + therm_on = thermometer == 2; REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on); } @@ -4057,7 +4184,7 @@ static void ar9003_hw_thermometer_apply(struct ath_hw *ah) static void ar9003_hw_thermo_cal_apply(struct ath_hw *ah) { - u32 data, ko, kg; + u32 data = 0, ko, kg; if (!AR_SREV_9462_20_OR_LATER(ah)) return; @@ -4074,6 +4201,37 @@ static void ar9003_hw_thermo_cal_apply(struct ath_hw *ah) } } +static void ar9003_hw_apply_minccapwr_thresh(struct ath_hw *ah, + bool is2ghz) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + const u_int32_t cca_ctrl[AR9300_MAX_CHAINS] = { + AR_PHY_CCA_CTRL_0, + AR_PHY_CCA_CTRL_1, + AR_PHY_CCA_CTRL_2, + }; + int chain; + u32 val; + + if (is2ghz) { + if (!(eep->base_ext1.misc_enable & BIT(2))) + return; + } else { + if (!(eep->base_ext1.misc_enable & BIT(3))) + return; + } + + for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { + if (!(ah->caps.tx_chainmask & BIT(chain))) + continue; + + val = ar9003_modal_header(ah, is2ghz)->noiseFloorThreshCh[chain]; + REG_RMW_FIELD(ah, cca_ctrl[chain], + AR_PHY_EXT_CCA0_THRESH62_1, val); + } + +} + static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -4085,9 +4243,10 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, ar9003_hw_xlna_bias_strength_apply(ah, is2ghz); ar9003_hw_atten_apply(ah, chan); ar9003_hw_quick_drop_apply(ah, chan->channel); - if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9550(ah)) + if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9531(ah)) ar9003_hw_internal_regulator_apply(ah); ar9003_hw_apply_tuning_caps(ah); + ar9003_hw_apply_minccapwr_thresh(ah, is2ghz); ar9003_hw_txend_to_xpa_off_apply(ah, is2ghz); ar9003_hw_thermometer_apply(ah); ar9003_hw_thermo_cal_apply(ah); @@ -4293,8 +4452,27 @@ static u8 ar9003_hw_eeprom_get_cck_tgt_pwr(struct ath_hw *ah, targetPowerArray, numPiers); } +static void ar9003_hw_selfgen_tpc_txpower(struct ath_hw *ah, + struct ath9k_channel *chan, + u8 *pwr_array) +{ + u32 val; + + /* target power values for self generated frames (ACK,RTS/CTS) */ + if (IS_CHAN_2GHZ(chan)) { + val = SM(pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_ACK) | + SM(pwr_array[ALL_TARGET_LEGACY_1L_5L], AR_TPC_CTS) | + SM(0x3f, AR_TPC_CHIRP) | SM(0x3f, AR_TPC_RPT); + } else { + val = SM(pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_ACK) | + SM(pwr_array[ALL_TARGET_LEGACY_6_24], AR_TPC_CTS) | + SM(0x3f, AR_TPC_CHIRP) | SM(0x3f, AR_TPC_RPT); + } + REG_WRITE(ah, AR_TPC, val); +} + /* Set tx power registers to array of values passed in */ -static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) +int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) { #define POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) /* make sure forced gain is not set */ @@ -4569,16 +4747,16 @@ static void ar9003_hw_get_target_power_eeprom(struct ath_hw *ah, } static int ar9003_hw_cal_pier_get(struct ath_hw *ah, - int mode, + bool is2ghz, int ipier, int ichain, int *pfrequency, int *pcorrection, - int *ptemperature, int *pvoltage) + int *ptemperature, int *pvoltage, + int *pnf_cal, int *pnf_power) { u8 *pCalPier; struct ar9300_cal_data_per_freq_op_loop *pCalPierStruct; - int is2GHz; struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; struct ath_common *common = ath9k_hw_common(ah); @@ -4589,17 +4767,7 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah, return -1; } - if (mode) { /* 5GHz */ - if (ipier >= AR9300_NUM_5G_CAL_PIERS) { - ath_dbg(common, EEPROM, - "Invalid 5GHz cal pier index, must be less than %d\n", - AR9300_NUM_5G_CAL_PIERS); - return -1; - } - pCalPier = &(eep->calFreqPier5G[ipier]); - pCalPierStruct = &(eep->calPierData5G[ichain][ipier]); - is2GHz = 0; - } else { + if (is2ghz) { if (ipier >= AR9300_NUM_2G_CAL_PIERS) { ath_dbg(common, EEPROM, "Invalid 2GHz cal pier index, must be less than %d\n", @@ -4609,13 +4777,25 @@ static int ar9003_hw_cal_pier_get(struct ath_hw *ah, pCalPier = &(eep->calFreqPier2G[ipier]); pCalPierStruct = &(eep->calPierData2G[ichain][ipier]); - is2GHz = 1; + } else { + if (ipier >= AR9300_NUM_5G_CAL_PIERS) { + ath_dbg(common, EEPROM, + "Invalid 5GHz cal pier index, must be less than %d\n", + AR9300_NUM_5G_CAL_PIERS); + return -1; + } + pCalPier = &(eep->calFreqPier5G[ipier]); + pCalPierStruct = &(eep->calPierData5G[ichain][ipier]); } - *pfrequency = ath9k_hw_fbin2freq(*pCalPier, is2GHz); + *pfrequency = ath9k_hw_fbin2freq(*pCalPier, is2ghz); *pcorrection = pCalPierStruct->refPower; *ptemperature = pCalPierStruct->tempMeas; *pvoltage = pCalPierStruct->voltMeas; + *pnf_cal = pCalPierStruct->rxTempMeas ? + N2DBM(pCalPierStruct->rxNoisefloorCal) : 0; + *pnf_power = pCalPierStruct->rxTempMeas ? + N2DBM(pCalPierStruct->rxNoisefloorPower) : 0; return 0; } @@ -4709,44 +4889,55 @@ static void ar9003_hw_power_control_override(struct ath_hw *ah, } tempslope: - if (AR_SREV_9550(ah)) { + if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) { + u8 txmask = (eep->baseEepHeader.txrxMask & 0xf0) >> 4; + /* * AR955x has tempSlope register for each chain. * Check whether temp_compensation feature is enabled or not. */ if (eep->baseEepHeader.featureEnable & 0x1) { if (frequency < 4000) { - REG_RMW_FIELD(ah, AR_PHY_TPC_19, - AR_PHY_TPC_19_ALPHA_THERM, - eep->base_ext2.tempSlopeLow); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, - AR_PHY_TPC_19_ALPHA_THERM, - eep->base_ext2.tempSlopeHigh); + if (txmask & BIT(0)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, + eep->base_ext2.tempSlopeLow); + if (txmask & BIT(1)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope); + if (txmask & BIT(2)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, + eep->base_ext2.tempSlopeHigh); } else { - REG_RMW_FIELD(ah, AR_PHY_TPC_19, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope1); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, - AR_PHY_TPC_19_ALPHA_THERM, - temp_slope2); + if (txmask & BIT(0)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope); + if (txmask & BIT(1)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope1); + if (txmask & BIT(2)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, + temp_slope2); } } else { /* * If temp compensation is not enabled, * set all registers to 0. */ - REG_RMW_FIELD(ah, AR_PHY_TPC_19, - AR_PHY_TPC_19_ALPHA_THERM, 0); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, - AR_PHY_TPC_19_ALPHA_THERM, 0); - REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, - AR_PHY_TPC_19_ALPHA_THERM, 0); + if (txmask & BIT(0)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19, + AR_PHY_TPC_19_ALPHA_THERM, 0); + if (txmask & BIT(1)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_ALPHA_THERM, 0); + if (txmask & BIT(2)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B2, + AR_PHY_TPC_19_ALPHA_THERM, 0); } } else { REG_RMW_FIELD(ah, AR_PHY_TPC_19, @@ -4766,24 +4957,27 @@ tempslope: static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) { int ichain, ipier, npier; - int mode; int lfrequency[AR9300_MAX_CHAINS], lcorrection[AR9300_MAX_CHAINS], - ltemperature[AR9300_MAX_CHAINS], lvoltage[AR9300_MAX_CHAINS]; + ltemperature[AR9300_MAX_CHAINS], lvoltage[AR9300_MAX_CHAINS], + lnf_cal[AR9300_MAX_CHAINS], lnf_pwr[AR9300_MAX_CHAINS]; int hfrequency[AR9300_MAX_CHAINS], hcorrection[AR9300_MAX_CHAINS], - htemperature[AR9300_MAX_CHAINS], hvoltage[AR9300_MAX_CHAINS]; + htemperature[AR9300_MAX_CHAINS], hvoltage[AR9300_MAX_CHAINS], + hnf_cal[AR9300_MAX_CHAINS], hnf_pwr[AR9300_MAX_CHAINS]; int fdiff; int correction[AR9300_MAX_CHAINS], - voltage[AR9300_MAX_CHAINS], temperature[AR9300_MAX_CHAINS]; - int pfrequency, pcorrection, ptemperature, pvoltage; + voltage[AR9300_MAX_CHAINS], temperature[AR9300_MAX_CHAINS], + nf_cal[AR9300_MAX_CHAINS], nf_pwr[AR9300_MAX_CHAINS]; + int pfrequency, pcorrection, ptemperature, pvoltage, + pnf_cal, pnf_pwr; struct ath_common *common = ath9k_hw_common(ah); + bool is2ghz = frequency < 4000; - mode = (frequency >= 4000); - if (mode) - npier = AR9300_NUM_5G_CAL_PIERS; - else + if (is2ghz) npier = AR9300_NUM_2G_CAL_PIERS; + else + npier = AR9300_NUM_5G_CAL_PIERS; for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { lfrequency[ichain] = 0; @@ -4792,9 +4986,10 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) /* identify best lower and higher frequency calibration measurement */ for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { for (ipier = 0; ipier < npier; ipier++) { - if (!ar9003_hw_cal_pier_get(ah, mode, ipier, ichain, + if (!ar9003_hw_cal_pier_get(ah, is2ghz, ipier, ichain, &pfrequency, &pcorrection, - &ptemperature, &pvoltage)) { + &ptemperature, &pvoltage, + &pnf_cal, &pnf_pwr)) { fdiff = frequency - pfrequency; /* @@ -4816,6 +5011,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) htemperature[ichain] = ptemperature; hvoltage[ichain] = pvoltage; + hnf_cal[ichain] = pnf_cal; + hnf_pwr[ichain] = pnf_pwr; } } if (fdiff >= 0) { @@ -4832,6 +5029,8 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) ltemperature[ichain] = ptemperature; lvoltage[ichain] = pvoltage; + lnf_cal[ichain] = pnf_cal; + lnf_pwr[ichain] = pnf_pwr; } } } @@ -4840,15 +5039,20 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) /* interpolate */ for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) { - ath_dbg(common, EEPROM, "ch=%d f=%d low=%d %d h=%d %d\n", + ath_dbg(common, EEPROM, + "ch=%d f=%d low=%d %d h=%d %d n=%d %d p=%d %d\n", ichain, frequency, lfrequency[ichain], lcorrection[ichain], hfrequency[ichain], - hcorrection[ichain]); + hcorrection[ichain], lnf_cal[ichain], + hnf_cal[ichain], lnf_pwr[ichain], + hnf_pwr[ichain]); /* they're the same, so just pick one */ if (hfrequency[ichain] == lfrequency[ichain]) { correction[ichain] = lcorrection[ichain]; voltage[ichain] = lvoltage[ichain]; temperature[ichain] = ltemperature[ichain]; + nf_cal[ichain] = lnf_cal[ichain]; + nf_pwr[ichain] = lnf_pwr[ichain]; } /* the low frequency is good */ else if (frequency - lfrequency[ichain] < 1000) { @@ -4872,12 +5076,26 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) hfrequency[ichain], lvoltage[ichain], hvoltage[ichain]); + + nf_cal[ichain] = interpolate(frequency, + lfrequency[ichain], + hfrequency[ichain], + lnf_cal[ichain], + hnf_cal[ichain]); + + nf_pwr[ichain] = interpolate(frequency, + lfrequency[ichain], + hfrequency[ichain], + lnf_pwr[ichain], + hnf_pwr[ichain]); } /* only low is good, use it */ else { correction[ichain] = lcorrection[ichain]; temperature[ichain] = ltemperature[ichain]; voltage[ichain] = lvoltage[ichain]; + nf_cal[ichain] = lnf_cal[ichain]; + nf_pwr[ichain] = lnf_pwr[ichain]; } } /* only high is good, use it */ @@ -4885,10 +5103,14 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) correction[ichain] = hcorrection[ichain]; temperature[ichain] = htemperature[ichain]; voltage[ichain] = hvoltage[ichain]; + nf_cal[ichain] = hnf_cal[ichain]; + nf_pwr[ichain] = hnf_pwr[ichain]; } else { /* nothing is good, presume 0???? */ correction[ichain] = 0; temperature[ichain] = 0; voltage[ichain] = 0; + nf_cal[ichain] = 0; + nf_pwr[ichain] = 0; } } @@ -4899,6 +5121,16 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) "for frequency=%d, calibration correction = %d %d %d\n", frequency, correction[0], correction[1], correction[2]); + /* Store calibrated noise floor values */ + for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) + if (is2ghz) { + ah->nf_2g.cal[ichain] = nf_cal[ichain]; + ah->nf_2g.pwr[ichain] = nf_pwr[ichain]; + } else { + ah->nf_5g.cal[ichain] = nf_cal[ichain]; + ah->nf_5g.pwr[ichain] = nf_pwr[ichain]; + } + return 0; } @@ -4983,6 +5215,10 @@ static u16 ar9003_hw_get_max_edge_power(struct ar9300_eeprom *eep, break; } } + + if (is2GHz && !twiceMaxEdgePower) + twiceMaxEdgePower = 60; + return twiceMaxEdgePower; } @@ -5209,10 +5445,9 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath_common *common = ath9k_hw_common(ah); - struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; - struct ar9300_modal_eep_header *modal_hdr; u8 targetPowerValT2[ar9300RateSize]; u8 target_power_val_t2_eep[ar9300RateSize]; + u8 targetPowerValT2_tpc[ar9300RateSize]; unsigned int i = 0, paprd_scale_factor = 0; u8 pwr_idx, min_pwridx = 0; @@ -5224,17 +5459,12 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, ar9003_hw_get_target_power_eeprom(ah, chan, targetPowerValT2); if (ar9003_is_paprd_enabled(ah)) { - if (IS_CHAN_2GHZ(chan)) - modal_hdr = &eep->modalHeader2G; - else - modal_hdr = &eep->modalHeader5G; - ah->paprd_ratemask = - le32_to_cpu(modal_hdr->papdRateMaskHt20) & + ar9003_get_paprd_rate_mask_ht20(ah, IS_CHAN_2GHZ(chan)) & AR9300_PAPRD_RATE_MASK; ah->paprd_ratemask_ht40 = - le32_to_cpu(modal_hdr->papdRateMaskHt40) & + ar9003_get_paprd_rate_mask_ht40(ah, IS_CHAN_2GHZ(chan)) & AR9300_PAPRD_RATE_MASK; paprd_scale_factor = ar9003_get_paprd_scale_factor(ah, chan); @@ -5264,6 +5494,9 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, twiceAntennaReduction, powerLimit); + memcpy(targetPowerValT2_tpc, targetPowerValT2, + sizeof(targetPowerValT2)); + if (ar9003_is_paprd_enabled(ah)) { for (i = 0; i < ar9300RateSize; i++) { if ((ah->paprd_ratemask & (1 << i)) && @@ -5297,6 +5530,30 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); ar9003_hw_calibration_apply(ah, chan->channel); ar9003_paprd_set_txpower(ah, chan, targetPowerValT2); + + ar9003_hw_selfgen_tpc_txpower(ah, chan, targetPowerValT2); + + /* TPC initializations */ + if (ah->tpc_enabled) { + u32 val; + + ar9003_hw_init_rate_txpower(ah, targetPowerValT2_tpc, chan); + + /* Enable TPC */ + REG_WRITE(ah, AR_PHY_PWRTX_MAX, + AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE); + /* Disable per chain power reduction */ + val = REG_READ(ah, AR_PHY_POWER_TX_SUB); + if (AR_SREV_9340(ah)) + REG_WRITE(ah, AR_PHY_POWER_TX_SUB, + val & 0xFFFFFFC0); + else + REG_WRITE(ah, AR_PHY_POWER_TX_SUB, + val & 0xFFFFF000); + } else { + /* Disable TPC */ + REG_WRITE(ah, AR_PHY_PWRTX_MAX, 0); + } } static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah, @@ -5324,27 +5581,42 @@ u8 *ar9003_get_spur_chan_ptr(struct ath_hw *ah, bool is2ghz) return ar9003_modal_header(ah, is2ghz)->spurChans; } +u32 ar9003_get_paprd_rate_mask_ht20(struct ath_hw *ah, bool is2ghz) +{ + return le32_to_cpu(ar9003_modal_header(ah, is2ghz)->papdRateMaskHt20); +} + +u32 ar9003_get_paprd_rate_mask_ht40(struct ath_hw *ah, bool is2ghz) +{ + return le32_to_cpu(ar9003_modal_header(ah, is2ghz)->papdRateMaskHt40); +} + unsigned int ar9003_get_paprd_scale_factor(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + bool is2ghz = IS_CHAN_2GHZ(chan); - if (IS_CHAN_2GHZ(chan)) - return MS(le32_to_cpu(eep->modalHeader2G.papdRateMaskHt20), + if (is2ghz) + return MS(ar9003_get_paprd_rate_mask_ht20(ah, is2ghz), AR9300_PAPRD_SCALE_1); else { if (chan->channel >= 5700) - return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20), - AR9300_PAPRD_SCALE_1); + return MS(ar9003_get_paprd_rate_mask_ht20(ah, is2ghz), + AR9300_PAPRD_SCALE_1); else if (chan->channel >= 5400) - return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40), - AR9300_PAPRD_SCALE_2); + return MS(ar9003_get_paprd_rate_mask_ht40(ah, is2ghz), + AR9300_PAPRD_SCALE_2); else - return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40), + return MS(ar9003_get_paprd_rate_mask_ht40(ah, is2ghz), AR9300_PAPRD_SCALE_1); } } +static u8 ar9003_get_eepmisc(struct ath_hw *ah) +{ + return ah->eeprom.ar9300_eep.baseEepHeader.opCapFlags.eepMisc; +} + const struct eeprom_ops eep_ar9300_ops = { .check_eeprom = ath9k_hw_ar9300_check_eeprom, .get_eeprom = ath9k_hw_ar9300_get_eeprom, @@ -5355,5 +5627,6 @@ const struct eeprom_ops eep_ar9300_ops = { .set_board_values = ath9k_hw_ar9300_set_board_values, .set_addac = ath9k_hw_ar9300_set_addac, .set_txpower = ath9k_hw_ar9300_set_txpower, - .get_spur_channel = ath9k_hw_ar9300_get_spur_channel + .get_spur_channel = ath9k_hw_ar9300_get_spur_channel, + .get_eepmisc = ar9003_get_eepmisc }; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index 874f6570bd1c..b91ef1250ba8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -38,7 +38,6 @@ #define AR9300_NUM_CTLS_2G 12 #define AR9300_NUM_BAND_EDGES_5G 8 #define AR9300_NUM_BAND_EDGES_2G 4 -#define AR9300_EEPMISC_BIG_ENDIAN 0x01 #define AR9300_EEPMISC_WOW 0x02 #define AR9300_CUSTOMER_DATA_SIZE 20 @@ -52,6 +51,8 @@ #define AR9300_PAPRD_SCALE_2 0x70000000 #define AR9300_PAPRD_SCALE_2_S 28 +#define AR9300_EEP_ANTDIV_CONTROL_DEFAULT_VALUE 0xc9 + /* Delta from which to start power to pdadc table */ /* This offset is used in both open loop and closed loop power control * schemes. In open loop power control, it is not really needed, but for @@ -61,6 +62,16 @@ */ #define AR9300_PWR_TABLE_OFFSET 0 +/* Noise power data definitions + * units are: 4 x dBm - NOISE_PWR_DATA_OFFSET + * (e.g. -25 = (-25/4 - 90) = -96.25 dBm) + * range (for 6 signed bits) is (-32 to 31) + offset => -122dBm to -59dBm + * resolution (2 bits) is 0.25dBm + */ +#define NOISE_PWR_DATA_OFFSET -90 +#define NOISE_PWR_DBM_2_INT(_p) ((((_p) + 3) >> 2) + NOISE_PWR_DATA_OFFSET) +#define N2DBM(_p) NOISE_PWR_DBM_2_INT(_p) + /* byte addressable */ #define AR9300_EEPROM_SIZE (16*1024) @@ -68,16 +79,19 @@ #define AR9300_BASE_ADDR 0x3ff #define AR9300_BASE_ADDR_512 0x1ff -#define AR9300_OTP_BASE \ - ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30000 : 0x14000) -#define AR9300_OTP_STATUS \ - ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30018 : 0x15f18) +/* AR5416_EEPMISC_BIG_ENDIAN not set indicates little endian */ +#define AR9300_EEPMISC_LITTLE_ENDIAN 0 + +#define AR9300_OTP_BASE(_ah) \ + ((AR_SREV_9340(_ah) || AR_SREV_9550(_ah)) ? 0x30000 : 0x14000) +#define AR9300_OTP_STATUS(_ah) \ + ((AR_SREV_9340(_ah) || AR_SREV_9550(_ah)) ? 0x31018 : 0x15f18) #define AR9300_OTP_STATUS_TYPE 0x7 #define AR9300_OTP_STATUS_VALID 0x4 #define AR9300_OTP_STATUS_ACCESS_BUSY 0x2 #define AR9300_OTP_STATUS_SM_BUSY 0x1 -#define AR9300_OTP_READ_DATA \ - ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3001c : 0x15f1c) +#define AR9300_OTP_READ_DATA(_ah) \ + ((AR_SREV_9340(_ah) || AR_SREV_9550(_ah)) ? 0x3101c : 0x15f1c) enum targetPowerHTRates { HT_TARGET_RATE_0_8_16, @@ -268,10 +282,20 @@ struct cal_ctl_data_5g { u8 ctlEdges[AR9300_NUM_BAND_EDGES_5G]; } __packed; +#define MAX_BASE_EXTENSION_FUTURE 2 + struct ar9300_BaseExtension_1 { u8 ant_div_control; - u8 future[3]; - u8 tempslopextension[8]; + u8 future[MAX_BASE_EXTENSION_FUTURE]; + /* + * misc_enable: + * + * BIT 0 - TX Gain Cap enable. + * BIT 1 - Uncompressed Checksum enable. + * BIT 2/3 - MinCCApwr enable 2g/5g. + */ + u8 misc_enable; + int8_t tempslopextension[8]; int8_t quick_drop_low; int8_t quick_drop_high; } __packed; @@ -334,12 +358,17 @@ struct ar9300_eeprom { s32 ar9003_hw_get_tx_gain_idx(struct ath_hw *ah); s32 ar9003_hw_get_rx_gain_idx(struct ath_hw *ah); +u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz); +u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz); u8 *ar9003_get_spur_chan_ptr(struct ath_hw *ah, bool is_2ghz); +u32 ar9003_get_paprd_rate_mask_ht20(struct ath_hw *ah, bool is2ghz); +u32 ar9003_get_paprd_rate_mask_ht40(struct ath_hw *ah, bool is2ghz); unsigned int ar9003_get_paprd_scale_factor(struct ath_hw *ah, struct ath9k_channel *chan); void ar9003_hw_internal_regulator_apply(struct ath_hw *ah); +int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray); #endif diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index d402cb32283f..6595eca74997 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -17,6 +17,7 @@ #include "hw.h" #include "ar9003_mac.h" #include "ar9003_2p2_initvals.h" +#include "ar9003_buffalo_initvals.h" #include "ar9485_initvals.h" #include "ar9340_initvals.h" #include "ar9330_1p1_initvals.h" @@ -26,6 +27,9 @@ #include "ar9462_2p0_initvals.h" #include "ar9462_2p1_initvals.h" #include "ar9565_1p0_initvals.h" +#include "ar9565_1p1_initvals.h" +#include "ar953x_initvals.h" +#include "ar956x_initvals.h" /* General hardware code for the AR9003 hadware family */ @@ -148,12 +152,16 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9340Modes_high_ob_db_tx_gain_table_1p0); INIT_INI_ARRAY(&ah->iniModesFastClock, - ar9340Modes_fast_clock_1p0); + ar9340Modes_fast_clock_1p0); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9340_1p0_baseband_core_txfir_coeff_japan_2484); + INIT_INI_ARRAY(&ah->ini_dfs, + ar9340_1p0_baseband_postamble_dfs_channel); if (!ah->is_clk_25mhz) INIT_INI_ARRAY(&ah->iniAdditional, ar9340_1p0_radio_core_40M); - } else if (AR_SREV_9485_11(ah)) { + } else if (AR_SREV_9485_11_OR_LATER(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9485_1_1_mac_core); @@ -187,17 +195,17 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniCckfirJapan2484, ar9485_1_1_baseband_core_txfir_coeff_japan_2484); - /* Load PCIE SERDES settings from INI */ - - /* Awake Setting */ - - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9485_1_1_pcie_phy_clkreq_disable_L1); - - /* Sleep Setting */ - - INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9485_1_1_pcie_phy_clkreq_disable_L1); + if (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9485_1_1_pll_on_cdr_on_clkreq_disable_L1); + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9485_1_1_pll_on_cdr_on_clkreq_disable_L1); + } else { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9485_1_1_pcie_phy_clkreq_disable_L1); + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9485_1_1_pcie_phy_clkreq_disable_L1); + } } else if (AR_SREV_9462_21(ah)) { INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_2p1_mac_core); @@ -223,6 +231,20 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9462_2p1_modes_fast_clock); INIT_INI_ARRAY(&ah->iniCckfirJapan2484, ar9462_2p1_baseband_core_txfir_coeff_japan_2484); + + /* Awake -> Sleep Setting */ + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D3)) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9462_2p1_pciephy_clkreq_disable_L1); + } + + /* Sleep -> Awake Setting */ + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D0)) { + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9462_2p1_pciephy_clkreq_disable_L1); + } } else if (AR_SREV_9462_20(ah)) { INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_2p0_mac_core); @@ -247,18 +269,25 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9462_2p0_soc_postamble); INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_rx_gain_table_2p0); + ar9462_2p0_common_rx_gain); /* Awake -> Sleep Setting */ - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9462_pciephy_clkreq_disable_L1_2p0); + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D3)) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9462_2p0_pciephy_clkreq_disable_L1); + } + /* Sleep -> Awake Setting */ - INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9462_pciephy_clkreq_disable_L1_2p0); + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D0)) { + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9462_2p0_pciephy_clkreq_disable_L1); + } /* Fast clock modal settings */ INIT_INI_ARRAY(&ah->iniModesFastClock, - ar9462_modes_fast_clock_2p0); + ar9462_2p0_modes_fast_clock); INIT_INI_ARRAY(&ah->iniCckfirJapan2484, ar9462_2p0_baseband_core_txfir_coeff_japan_2484); @@ -298,6 +327,89 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) /* Fast clock modal settings */ INIT_INI_ARRAY(&ah->iniModesFastClock, ar955x_1p0_modes_fast_clock); + } else if (AR_SREV_9531(ah)) { + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], + qca953x_1p0_mac_core); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + qca953x_1p0_mac_postamble); + if (AR_SREV_9531_20(ah)) { + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + qca953x_2p0_baseband_core); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + qca953x_2p0_baseband_postamble); + } else { + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + qca953x_1p0_baseband_core); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + qca953x_1p0_baseband_postamble); + } + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + qca953x_1p0_radio_core); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + qca953x_1p0_radio_postamble); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + qca953x_1p0_soc_preamble); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + qca953x_1p0_soc_postamble); + + if (AR_SREV_9531_20(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca953x_2p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca953x_2p0_common_wo_xlna_rx_gain_bounds); + } else { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca953x_1p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca953x_1p0_common_wo_xlna_rx_gain_bounds); + } + + if (AR_SREV_9531_20(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_2p0_modes_no_xpa_tx_gain_table); + else if (AR_SREV_9531_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p1_modes_no_xpa_tx_gain_table); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p0_modes_no_xpa_tx_gain_table); + + INIT_INI_ARRAY(&ah->iniModesFastClock, + qca953x_1p0_modes_fast_clock); + } else if (AR_SREV_9561(ah)) { + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], + qca956x_1p0_mac_core); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + qca956x_1p0_mac_postamble); + + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + qca956x_1p0_baseband_core); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + qca956x_1p0_baseband_postamble); + + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + qca956x_1p0_radio_core); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + qca956x_1p0_radio_postamble); + + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + qca956x_1p0_soc_preamble); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + qca956x_1p0_soc_postamble); + + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca956x_1p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca956x_1p0_common_wo_xlna_rx_gain_bounds); + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_no_xpa_tx_gain_table); + + INIT_INI_ARRAY(&ah->ini_dfs, + qca956x_1p0_baseband_postamble_dfs_channel); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + qca956x_1p0_baseband_core_txfir_coeff_japan_2484); + INIT_INI_ARRAY(&ah->iniModesFastClock, + qca956x_1p0_modes_fast_clock); } else if (AR_SREV_9580(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], @@ -330,7 +442,55 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9580_1p0_low_ob_db_tx_gain_table); INIT_INI_ARRAY(&ah->iniModesFastClock, - ar9580_1p0_modes_fast_clock); + ar9580_1p0_modes_fast_clock); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9580_1p0_baseband_core_txfir_coeff_japan_2484); + INIT_INI_ARRAY(&ah->ini_dfs, + ar9580_1p0_baseband_postamble_dfs_channel); + } else if (AR_SREV_9565_11_OR_LATER(ah)) { + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], + ar9565_1p1_mac_core); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + ar9565_1p1_mac_postamble); + + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + ar9565_1p1_baseband_core); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + ar9565_1p1_baseband_postamble); + + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + ar9565_1p1_radio_core); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + ar9565_1p1_radio_postamble); + + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + ar9565_1p1_soc_preamble); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + ar9565_1p1_soc_postamble); + + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9565_1p1_Common_rx_gain_table); + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9565_1p1_Modes_lowest_ob_db_tx_gain_table); + + /* Awake -> Sleep Setting */ + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D3)) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9565_1p1_pciephy_clkreq_disable_L1); + } + + /* Sleep -> Awake Setting */ + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D0)) { + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9565_1p1_pciephy_clkreq_disable_L1); + } + + INIT_INI_ARRAY(&ah->iniModesFastClock, + ar9565_1p1_modes_fast_clock); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9565_1p1_baseband_core_txfir_coeff_japan_2484); } else if (AR_SREV_9565(ah)) { INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9565_1p0_mac_core); @@ -357,13 +517,24 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p0_Modes_lowest_ob_db_tx_gain_table); - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9565_1p0_pciephy_clkreq_disable_L1); - INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9565_1p0_pciephy_clkreq_disable_L1); + /* Awake -> Sleep Setting */ + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D3)) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9565_1p0_pciephy_clkreq_disable_L1); + } + + /* Sleep -> Awake Setting */ + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D0)) { + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9565_1p0_pciephy_clkreq_disable_L1); + } INIT_INI_ARRAY(&ah->iniModesFastClock, ar9565_1p0_modes_fast_clock); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9565_1p0_baseband_core_txfir_coeff_japan_2484); } else { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], @@ -409,7 +580,11 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) /* Fast clock modal settings */ INIT_INI_ARRAY(&ah->iniModesFastClock, - ar9300Modes_fast_clock_2p2); + ar9300Modes_fast_clock_2p2); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + ar9300_2p2_baseband_core_txfir_coeff_japan_2484); + INIT_INI_ARRAY(&ah->ini_dfs, + ar9300_2p2_baseband_postamble_dfs_channel); } } @@ -424,12 +599,24 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9340Modes_lowest_ob_db_tx_gain_table_1p0); - else if (AR_SREV_9485_11(ah)) + else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485_modes_lowest_ob_db_tx_gain_1_1); else if (AR_SREV_9550(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar955x_1p0_modes_xpa_tx_gain_table); + else if (AR_SREV_9531_10(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p0_modes_xpa_tx_gain_table); + else if (AR_SREV_9531_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p1_modes_xpa_tx_gain_table); + else if (AR_SREV_9531_20(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_2p0_modes_xpa_tx_gain_table); + else if (AR_SREV_9561(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_xpa_tx_gain_table); else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_lowest_ob_db_tx_gain_table); @@ -438,7 +625,10 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) ar9462_2p1_modes_low_ob_db_tx_gain); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9462_modes_low_ob_db_tx_gain_table_2p0); + ar9462_2p0_modes_low_ob_db_tx_gain); + else if (AR_SREV_9565_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9565_1p1_modes_low_ob_db_tx_gain_table); else if (AR_SREV_9565(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p0_modes_low_ob_db_tx_gain_table); @@ -458,7 +648,7 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9340Modes_high_ob_db_tx_gain_table_1p0); - else if (AR_SREV_9485_11(ah)) + else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_high_ob_db_tx_gain_1_1); else if (AR_SREV_9580(ah)) @@ -467,12 +657,28 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) else if (AR_SREV_9550(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar955x_1p0_modes_no_xpa_tx_gain_table); + else if (AR_SREV_9531(ah)) { + if (AR_SREV_9531_20(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_2p0_modes_no_xpa_tx_gain_table); + else if (AR_SREV_9531_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p1_modes_no_xpa_tx_gain_table); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p0_modes_no_xpa_tx_gain_table); + } else if (AR_SREV_9561(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_no_xpa_tx_gain_table); else if (AR_SREV_9462_21(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9462_2p1_modes_high_ob_db_tx_gain); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9462_modes_high_ob_db_tx_gain_table_2p0); + ar9462_2p0_modes_high_ob_db_tx_gain); + else if (AR_SREV_9565_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9565_1p1_modes_high_ob_db_tx_gain_table); else if (AR_SREV_9565(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p0_modes_high_ob_db_tx_gain_table); @@ -492,12 +698,21 @@ static void ar9003_tx_gain_table_mode2(struct ath_hw *ah) else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9340Modes_low_ob_db_tx_gain_table_1p0); - else if (AR_SREV_9485_11(ah)) + else if (AR_SREV_9531_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p1_modes_no_xpa_low_power_tx_gain_table); + else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_low_ob_db_tx_gain_1_1); else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_low_ob_db_tx_gain_table); + else if (AR_SREV_9561(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_no_xpa_low_ob_db_tx_gain_table); + else if (AR_SREV_9565_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9565_1p1_modes_low_ob_db_tx_gain_table); else if (AR_SREV_9565(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p0_modes_low_ob_db_tx_gain_table); @@ -517,18 +732,26 @@ static void ar9003_tx_gain_table_mode3(struct ath_hw *ah) else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9340Modes_high_power_tx_gain_table_1p0); - else if (AR_SREV_9485_11(ah)) + else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_high_power_tx_gain_1_1); else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_high_power_tx_gain_table); + else if (AR_SREV_9565_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9565_1p1_modes_high_power_tx_gain_table); else if (AR_SREV_9565(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p0_modes_high_power_tx_gain_table); - else - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_high_power_tx_gain_table_2p2); + else { + if (ah->config.tx_gain_buffalo) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_high_power_tx_gain_table_buffalo); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_high_power_tx_gain_table_2p2); + } } static void ar9003_tx_gain_table_mode4(struct ath_hw *ah) @@ -544,7 +767,7 @@ static void ar9003_tx_gain_table_mode4(struct ath_hw *ah) ar9462_2p1_modes_mix_ob_db_tx_gain); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9462_modes_mix_ob_db_tx_gain_table_2p0); + ar9462_2p0_modes_mix_ob_db_tx_gain); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_mixed_ob_db_tx_gain_table_2p2); @@ -552,15 +775,15 @@ static void ar9003_tx_gain_table_mode4(struct ath_hw *ah) static void ar9003_tx_gain_table_mode5(struct ath_hw *ah) { - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_green_ob_db_tx_gain_1_1); - else if (AR_SREV_9340(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9340Modes_ub124_tx_gain_table_1p0); else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_type5_tx_gain_table); + else if (AR_SREV_9561(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca956x_1p0_modes_no_xpa_green_tx_gain_table); else if (AR_SREV_9300_22(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9300Modes_type5_tx_gain_table_2p2); @@ -571,7 +794,7 @@ static void ar9003_tx_gain_table_mode6(struct ath_hw *ah) if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9340Modes_low_ob_db_and_spur_tx_gain_table_1p0); - else if (AR_SREV_9485_11(ah)) + else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_green_spur_ob_db_tx_gain_1_1); else if (AR_SREV_9580(ah)) @@ -579,6 +802,13 @@ static void ar9003_tx_gain_table_mode6(struct ath_hw *ah) ar9580_1p0_type6_tx_gain_table); } +static void ar9003_tx_gain_table_mode7(struct ath_hw *ah) +{ + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340_cus227_tx_gain_table_1p0); +} + typedef void (*ath_txgain_tab)(struct ath_hw *ah); static void ar9003_tx_gain_table_apply(struct ath_hw *ah) @@ -591,6 +821,7 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) ar9003_tx_gain_table_mode4, ar9003_tx_gain_table_mode5, ar9003_tx_gain_table_mode6, + ar9003_tx_gain_table_mode7, }; int idx = ar9003_hw_get_tx_gain_idx(ah); @@ -611,7 +842,7 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9340Common_rx_gain_table_1p0); - else if (AR_SREV_9485_11(ah)) + else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9485_common_rx_gain_1_1); else if (AR_SREV_9550(ah)) { @@ -619,6 +850,18 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) ar955x_1p0_common_rx_gain_table); INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, ar955x_1p0_common_rx_gain_bounds); + } else if (AR_SREV_9531(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca953x_1p0_common_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca953x_1p0_common_rx_gain_bounds); + } else if (AR_SREV_9561(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca956x_1p0_common_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca956x_1p0_common_rx_gain_bounds); + INIT_INI_ARRAY(&ah->ini_modes_rxgain_xlna, + qca956x_1p0_xlna_only); } else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9580_1p0_rx_gain_table); @@ -627,7 +870,13 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) ar9462_2p1_common_rx_gain); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_rx_gain_table_2p0); + ar9462_2p0_common_rx_gain); + else if (AR_SREV_9565_11(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9565_1p1_Common_rx_gain_table); + else if (AR_SREV_9565(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9565_1p0_Common_rx_gain_table); else INIT_INI_ARRAY(&ah->iniModesRxGain, ar9300Common_rx_gain_table_2p2); @@ -644,7 +893,7 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9340Common_wo_xlna_rx_gain_table_1p0); - else if (AR_SREV_9485_11(ah)) + else if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9485Common_wo_xlna_rx_gain_1_1); else if (AR_SREV_9462_21(ah)) @@ -652,15 +901,33 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) ar9462_2p1_common_wo_xlna_rx_gain); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_wo_xlna_rx_gain_table_2p0); + ar9462_2p0_common_wo_xlna_rx_gain); else if (AR_SREV_9550(ah)) { INIT_INI_ARRAY(&ah->iniModesRxGain, ar955x_1p0_common_wo_xlna_rx_gain_table); INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, ar955x_1p0_common_wo_xlna_rx_gain_bounds); + } else if (AR_SREV_9531_10(ah) || AR_SREV_9531_11(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca953x_1p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca953x_1p0_common_wo_xlna_rx_gain_bounds); + } else if (AR_SREV_9531_20(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca953x_2p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca953x_2p0_common_wo_xlna_rx_gain_bounds); + } else if (AR_SREV_9561(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca956x_1p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca956x_1p0_common_wo_xlna_rx_gain_bounds); } else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9580_1p0_wo_xlna_rx_gain_table); + else if (AR_SREV_9565_11(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9565_1p1_common_wo_xlna_rx_gain_table); else if (AR_SREV_9565(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9565_1p0_common_wo_xlna_rx_gain_table); @@ -678,16 +945,16 @@ static void ar9003_rx_gain_table_mode2(struct ath_hw *ah) ar9462_2p1_baseband_core_mix_rxgain); INIT_INI_ARRAY(&ah->ini_modes_rxgain_bb_postamble, ar9462_2p1_baseband_postamble_mix_rxgain); - INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna, + INIT_INI_ARRAY(&ah->ini_modes_rxgain_xlna, ar9462_2p1_baseband_postamble_5g_xlna); } else if (AR_SREV_9462_20(ah)) { INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_mixed_rx_gain_table_2p0); + ar9462_2p0_common_mixed_rx_gain); INIT_INI_ARRAY(&ah->ini_modes_rxgain_bb_core, ar9462_2p0_baseband_core_mix_rxgain); INIT_INI_ARRAY(&ah->ini_modes_rxgain_bb_postamble, ar9462_2p0_baseband_postamble_mix_rxgain); - INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna, + INIT_INI_ARRAY(&ah->ini_modes_rxgain_xlna, ar9462_2p0_baseband_postamble_5g_xlna); } } @@ -696,13 +963,13 @@ static void ar9003_rx_gain_table_mode3(struct ath_hw *ah) { if (AR_SREV_9462_21(ah)) { INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_2p1_common_5g_xlna_only_rx_gain); - INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna, + ar9462_2p1_common_5g_xlna_only_rxgain); + INIT_INI_ARRAY(&ah->ini_modes_rxgain_xlna, ar9462_2p1_baseband_postamble_5g_xlna); } else if (AR_SREV_9462_20(ah)) { INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_2p0_5g_xlna_only_rxgain); - INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna, + ar9462_2p0_common_5g_xlna_only_rxgain); + INIT_INI_ARRAY(&ah->ini_modes_rxgain_xlna, ar9462_2p0_baseband_postamble_5g_xlna); } } @@ -745,49 +1012,185 @@ static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah) static void ar9003_hw_configpcipowersave(struct ath_hw *ah, bool power_off) { + unsigned int i; + struct ar5416IniArray *array; + + /* + * Increase L1 Entry Latency. Some WB222 boards don't have + * this change in eeprom/OTP. + * + */ + if (AR_SREV_9462(ah)) { + u32 val = ah->config.aspm_l1_fix; + if ((val & 0xff000000) == 0x17000000) { + val &= 0x00ffffff; + val |= 0x27000000; + REG_WRITE(ah, 0x570c, val); + } + } + /* Nothing to do on restore for 11N */ if (!power_off /* !restore */) { /* set bit 19 to allow forcing of pcie core into L1 state */ - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); - - /* Several PCIe massages to ensure proper behaviour */ - if (ah->config.pcie_waen) - REG_WRITE(ah, AR_WA, ah->config.pcie_waen); - else - REG_WRITE(ah, AR_WA, ah->WARegVal); + REG_SET_BIT(ah, AR_PCIE_PM_CTRL(ah), AR_PCIE_PM_CTRL_ENA); + REG_WRITE(ah, AR_WA(ah), ah->WARegVal); } /* - * Configire PCIE after Ini init. SERDES values now come from ini file + * Configure PCIE after Ini init. SERDES values now come from ini file * This enables PCIe low power mode. */ - if (ah->config.pcieSerDesWrite) { - unsigned int i; - struct ar5416IniArray *array; + array = power_off ? &ah->iniPcieSerdes : + &ah->iniPcieSerdesLowPower; + + for (i = 0; i < array->ia_rows; i++) { + REG_WRITE(ah, + INI_RA(array, i, 0), + INI_RA(array, i, 1)); + } +} + +static void ar9003_hw_init_hang_checks(struct ath_hw *ah) +{ + /* + * All chips support detection of BB/MAC hangs. + */ + ah->config.hw_hang_checks |= HW_BB_WATCHDOG; + ah->config.hw_hang_checks |= HW_MAC_HANG; + + /* + * This is not required for AR9580 1.0 + */ + if (AR_SREV_9300_22(ah)) + ah->config.hw_hang_checks |= HW_PHYRESTART_CLC_WAR; + + if (AR_SREV_9330(ah)) + ah->bb_watchdog_timeout_ms = 85; + else + ah->bb_watchdog_timeout_ms = 25; +} - array = power_off ? &ah->iniPcieSerdes : - &ah->iniPcieSerdesLowPower; +/* + * MAC HW hang check + * ================= + * + * Signature: dcu_chain_state is 0x6 and dcu_complete_state is 0x1. + * + * The state of each DCU chain (mapped to TX queues) is available from these + * DMA debug registers: + * + * Chain 0 state : Bits 4:0 of AR_DMADBG_4 + * Chain 1 state : Bits 9:5 of AR_DMADBG_4 + * Chain 2 state : Bits 14:10 of AR_DMADBG_4 + * Chain 3 state : Bits 19:15 of AR_DMADBG_4 + * Chain 4 state : Bits 24:20 of AR_DMADBG_4 + * Chain 5 state : Bits 29:25 of AR_DMADBG_4 + * Chain 6 state : Bits 4:0 of AR_DMADBG_5 + * Chain 7 state : Bits 9:5 of AR_DMADBG_5 + * Chain 8 state : Bits 14:10 of AR_DMADBG_5 + * Chain 9 state : Bits 19:15 of AR_DMADBG_5 + * + * The DCU chain state "0x6" means "WAIT_FRDONE" - wait for TX frame to be done. + */ - for (i = 0; i < array->ia_rows; i++) { - REG_WRITE(ah, - INI_RA(array, i, 0), - INI_RA(array, i, 1)); +#define NUM_STATUS_READS 50 + +static bool ath9k_hw_verify_hang(struct ath_hw *ah, unsigned int queue) +{ + u32 dma_dbg_chain, dma_dbg_complete; + u8 dcu_chain_state, dcu_complete_state; + unsigned int dbg_reg, reg_offset; + int i; + + if (queue < 6) { + dbg_reg = AR_DMADBG_4; + reg_offset = queue * 5; + } else { + dbg_reg = AR_DMADBG_5; + reg_offset = (queue - 6) * 5; + } + + for (i = 0; i < NUM_STATUS_READS; i++) { + dma_dbg_chain = REG_READ(ah, dbg_reg); + dma_dbg_complete = REG_READ(ah, AR_DMADBG_6); + + dcu_chain_state = (dma_dbg_chain >> reg_offset) & 0x1f; + dcu_complete_state = dma_dbg_complete & 0x3; + + if ((dcu_chain_state != 0x6) || (dcu_complete_state != 0x1)) + return false; + } + + ath_dbg(ath9k_hw_common(ah), RESET, + "MAC Hang signature found for queue: %d\n", queue); + + return true; +} + +static bool ar9003_hw_detect_mac_hang(struct ath_hw *ah) +{ + u32 dma_dbg_4, dma_dbg_5, dma_dbg_6, chk_dbg; + u8 dcu_chain_state, dcu_complete_state; + bool dcu_wait_frdone = false; + unsigned long chk_dcu = 0; + unsigned int reg_offset; + unsigned int i = 0; + + dma_dbg_4 = REG_READ(ah, AR_DMADBG_4); + dma_dbg_5 = REG_READ(ah, AR_DMADBG_5); + dma_dbg_6 = REG_READ(ah, AR_DMADBG_6); + + dcu_complete_state = dma_dbg_6 & 0x3; + if (dcu_complete_state != 0x1) + goto exit; + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (i < 6) { + chk_dbg = dma_dbg_4; + reg_offset = i * 5; + } else { + chk_dbg = dma_dbg_5; + reg_offset = (i - 6) * 5; + } + + dcu_chain_state = (chk_dbg >> reg_offset) & 0x1f; + if (dcu_chain_state == 0x6) { + dcu_wait_frdone = true; + chk_dcu |= BIT(i); + } + } + + if ((dcu_complete_state == 0x1) && dcu_wait_frdone) { + for_each_set_bit(i, &chk_dcu, ATH9K_NUM_TX_QUEUES) { + if (ath9k_hw_verify_hang(ah, i)) + return true; } } +exit: + return false; } -/* Sets up the AR9003 hardware familiy callbacks */ +/* Sets up the AR9003 hardware family callbacks */ void ar9003_hw_attach_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); struct ath_hw_ops *ops = ath9k_hw_ops(ah); ar9003_hw_init_mode_regs(ah); + + if (AR_SREV_9003_PCOEM(ah)) { + WARN_ON(!ah->iniPcieSerdes.ia_array); + WARN_ON(!ah->iniPcieSerdesLowPower.ia_array); + } + priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs; + priv_ops->init_hang_checks = ar9003_hw_init_hang_checks; + priv_ops->detect_mac_hang = ar9003_hw_detect_mac_hang; ops->config_pci_powersave = ar9003_hw_configpcipowersave; ar9003_hw_attach_phy_ops(ah); ar9003_hw_attach_calib_ops(ah); ar9003_hw_attach_mac_ops(ah); + ar9003_hw_attach_aic_ops(ah); } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 5163abd3937c..a8bc003077dc 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -39,47 +39,47 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) (i->qcu << AR_TxQcuNum_S) | desc_len; checksum += val; - ACCESS_ONCE(ads->info) = val; + WRITE_ONCE(ads->info, val); checksum += i->link; - ACCESS_ONCE(ads->link) = i->link; + WRITE_ONCE(ads->link, i->link); checksum += i->buf_addr[0]; - ACCESS_ONCE(ads->data0) = i->buf_addr[0]; + WRITE_ONCE(ads->data0, i->buf_addr[0]); checksum += i->buf_addr[1]; - ACCESS_ONCE(ads->data1) = i->buf_addr[1]; + WRITE_ONCE(ads->data1, i->buf_addr[1]); checksum += i->buf_addr[2]; - ACCESS_ONCE(ads->data2) = i->buf_addr[2]; + WRITE_ONCE(ads->data2, i->buf_addr[2]); checksum += i->buf_addr[3]; - ACCESS_ONCE(ads->data3) = i->buf_addr[3]; + WRITE_ONCE(ads->data3, i->buf_addr[3]); checksum += (val = (i->buf_len[0] << AR_BufLen_S) & AR_BufLen); - ACCESS_ONCE(ads->ctl3) = val; + WRITE_ONCE(ads->ctl3, val); checksum += (val = (i->buf_len[1] << AR_BufLen_S) & AR_BufLen); - ACCESS_ONCE(ads->ctl5) = val; + WRITE_ONCE(ads->ctl5, val); checksum += (val = (i->buf_len[2] << AR_BufLen_S) & AR_BufLen); - ACCESS_ONCE(ads->ctl7) = val; + WRITE_ONCE(ads->ctl7, val); checksum += (val = (i->buf_len[3] << AR_BufLen_S) & AR_BufLen); - ACCESS_ONCE(ads->ctl9) = val; + WRITE_ONCE(ads->ctl9, val); checksum = (u16) (((checksum & 0xffff) + (checksum >> 16)) & 0xffff); - ACCESS_ONCE(ads->ctl10) = checksum; + WRITE_ONCE(ads->ctl10, checksum); if (i->is_first || i->is_last) { - ACCESS_ONCE(ads->ctl13) = set11nTries(i->rates, 0) + WRITE_ONCE(ads->ctl13, set11nTries(i->rates, 0) | set11nTries(i->rates, 1) | set11nTries(i->rates, 2) | set11nTries(i->rates, 3) | (i->dur_update ? AR_DurUpdateEna : 0) - | SM(0, AR_BurstDur); + | SM(0, AR_BurstDur)); - ACCESS_ONCE(ads->ctl14) = set11nRate(i->rates, 0) + WRITE_ONCE(ads->ctl14, set11nRate(i->rates, 0) | set11nRate(i->rates, 1) | set11nRate(i->rates, 2) - | set11nRate(i->rates, 3); + | set11nRate(i->rates, 3)); } else { - ACCESS_ONCE(ads->ctl13) = 0; - ACCESS_ONCE(ads->ctl14) = 0; + WRITE_ONCE(ads->ctl13, 0); + WRITE_ONCE(ads->ctl14, 0); } ads->ctl20 = 0; @@ -89,25 +89,25 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) ctl17 = SM(i->keytype, AR_EncrType); if (!i->is_first) { - ACCESS_ONCE(ads->ctl11) = 0; - ACCESS_ONCE(ads->ctl12) = i->is_last ? 0 : AR_TxMore; - ACCESS_ONCE(ads->ctl15) = 0; - ACCESS_ONCE(ads->ctl16) = 0; - ACCESS_ONCE(ads->ctl17) = ctl17; - ACCESS_ONCE(ads->ctl18) = 0; - ACCESS_ONCE(ads->ctl19) = 0; + WRITE_ONCE(ads->ctl11, 0); + WRITE_ONCE(ads->ctl12, i->is_last ? 0 : AR_TxMore); + WRITE_ONCE(ads->ctl15, 0); + WRITE_ONCE(ads->ctl16, 0); + WRITE_ONCE(ads->ctl17, ctl17); + WRITE_ONCE(ads->ctl18, 0); + WRITE_ONCE(ads->ctl19, 0); return; } - ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen) + WRITE_ONCE(ads->ctl11, (i->pkt_len & AR_FrameLen) | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) - | SM(i->txpower, AR_XmitPower) + | SM(i->txpower[0], AR_XmitPower0) | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) | (i->flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0) | (i->flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) | (i->flags & ATH9K_TXDESC_RTSENA ? AR_RTSEnable : - (i->flags & ATH9K_TXDESC_CTSENA ? AR_CTSEnable : 0)); + (i->flags & ATH9K_TXDESC_CTSENA ? AR_CTSEnable : 0))); ctl12 = (i->keyix != ATH9K_TXKEYIX_INVALID ? SM(i->keyix, AR_DestIdx) : 0) @@ -120,7 +120,7 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) switch (i->aggr) { case AGGR_BUF_FIRST: ctl17 |= SM(i->aggr_len, AR_AggrLen); - /* fall through */ + fallthrough; case AGGR_BUF_MIDDLE: ctl12 |= AR_IsAggr | AR_MoreAggr; ctl17 |= SM(i->ndelim, AR_PadDelim); @@ -135,22 +135,27 @@ ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) val = (i->flags & ATH9K_TXDESC_PAPRD) >> ATH9K_TXDESC_PAPRD_S; ctl12 |= SM(val, AR_PAPRDChainMask); - ACCESS_ONCE(ads->ctl12) = ctl12; - ACCESS_ONCE(ads->ctl17) = ctl17; + WRITE_ONCE(ads->ctl12, ctl12); + WRITE_ONCE(ads->ctl17, ctl17); - ACCESS_ONCE(ads->ctl15) = set11nPktDurRTSCTS(i->rates, 0) - | set11nPktDurRTSCTS(i->rates, 1); + WRITE_ONCE(ads->ctl15, set11nPktDurRTSCTS(i->rates, 0) + | set11nPktDurRTSCTS(i->rates, 1)); - ACCESS_ONCE(ads->ctl16) = set11nPktDurRTSCTS(i->rates, 2) - | set11nPktDurRTSCTS(i->rates, 3); + WRITE_ONCE(ads->ctl16, set11nPktDurRTSCTS(i->rates, 2) + | set11nPktDurRTSCTS(i->rates, 3)); - ACCESS_ONCE(ads->ctl18) = set11nRateFlags(i->rates, 0) - | set11nRateFlags(i->rates, 1) - | set11nRateFlags(i->rates, 2) - | set11nRateFlags(i->rates, 3) - | SM(i->rtscts_rate, AR_RTSCTSRate); + WRITE_ONCE(ads->ctl18, + set11nRateFlags(i->rates, 0) | set11nChainSel(i->rates, 0) + | set11nRateFlags(i->rates, 1) | set11nChainSel(i->rates, 1) + | set11nRateFlags(i->rates, 2) | set11nChainSel(i->rates, 2) + | set11nRateFlags(i->rates, 3) | set11nChainSel(i->rates, 3) + | SM(i->rtscts_rate, AR_RTSCTSRate)); - ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding; + WRITE_ONCE(ads->ctl19, AR_Not_Sounding); + + WRITE_ONCE(ads->ctl20, SM(i->txpower[1], AR_XmitPower1)); + WRITE_ONCE(ads->ctl21, SM(i->txpower[2], AR_XmitPower2)); + WRITE_ONCE(ads->ctl22, SM(i->txpower[3], AR_XmitPower3)); } static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads) @@ -175,7 +180,8 @@ static void ar9003_hw_set_desc_link(void *ds, u32 ds_link) ads->ctl10 |= ar9003_calc_ptr_chksum(ads); } -static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) +static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked, + u32 *sync_cause_p) { u32 isr = 0; u32 mask2 = 0; @@ -187,16 +193,16 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) if (ath9k_hw_mci_is_enabled(ah)) async_mask |= AR_INTR_ASYNC_MASK_MCI; - async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE); + async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE(ah)); if (async_cause & async_mask) { - if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) + if ((REG_READ(ah, AR_RTC_STATUS(ah)) & AR_RTC_STATUS_M(ah)) == AR_RTC_STATUS_ON) isr = REG_READ(ah, AR_ISR); } - sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT; + sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE(ah)) & AR_INTR_SYNC_DEFAULT; *masked = 0; @@ -274,7 +280,7 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) u32 s5; if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) - s5 = REG_READ(ah, AR_ISR_S5_S); + s5 = REG_READ(ah, AR_ISR_S5_S(ah)); else s5 = REG_READ(ah, AR_ISR_S5); @@ -310,7 +316,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) ar9003_mci_get_isr(ah, masked); if (sync_cause) { - ath9k_debug_sync_cause(common, sync_cause); + if (sync_cause_p) + *sync_cause_p = sync_cause; fatal_int = (sync_cause & (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) @@ -338,8 +345,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) ath_dbg(common, INTERRUPT, "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); - REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); - (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); + REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR(ah), sync_cause); + (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR(ah)); } return true; @@ -353,7 +360,7 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, ads = &ah->ts_ring[ah->ts_tail]; - status = ACCESS_ONCE(ads->status8); + status = READ_ONCE(ads->status8); if ((status & AR_TxDone) == 0) return -EINPROGRESS; @@ -379,7 +386,7 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, if (status & AR_TxOpExceeded) ts->ts_status |= ATH9K_TXERR_XTXOP; - status = ACCESS_ONCE(ads->status2); + status = READ_ONCE(ads->status2); ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00); ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01); ts->ts_rssi_ctl2 = MS(status, AR_TxRSSIAnt02); @@ -389,7 +396,7 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->ba_high = ads->status6; } - status = ACCESS_ONCE(ads->status3); + status = READ_ONCE(ads->status3); if (status & AR_ExcessiveRetries) ts->ts_status |= ATH9K_TXERR_XRETRY; if (status & AR_Filtered) @@ -414,7 +421,7 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->ts_longretry = MS(status, AR_DataFailCnt); ts->ts_virtcol = MS(status, AR_VirtRetryCnt); - status = ACCESS_ONCE(ads->status7); + status = READ_ONCE(ads->status7); ts->ts_rssi = MS(status, AR_TxRSSICombined); ts->ts_rssi_ext0 = MS(status, AR_TxRSSIAnt10); ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11); @@ -425,6 +432,24 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, return 0; } +static int ar9003_hw_get_duration(struct ath_hw *ah, const void *ds, int index) +{ + const struct ar9003_txc *adc = ds; + + switch (index) { + case 0: + return MS(READ_ONCE(adc->ctl15), AR_PacketDur0); + case 1: + return MS(READ_ONCE(adc->ctl15), AR_PacketDur1); + case 2: + return MS(READ_ONCE(adc->ctl16), AR_PacketDur2); + case 3: + return MS(READ_ONCE(adc->ctl16), AR_PacketDur3); + default: + return 0; + } +} + void ar9003_hw_attach_mac_ops(struct ath_hw *hw) { struct ath_hw_ops *ops = ath9k_hw_ops(hw); @@ -434,6 +459,7 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw) ops->get_isr = ar9003_hw_get_isr; ops->set_txdesc = ar9003_set_txdesc; ops->proc_txdesc = ar9003_hw_proc_txdesc; + ops->get_duration = ar9003_hw_get_duration; } void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) @@ -455,7 +481,7 @@ EXPORT_SYMBOL(ath9k_hw_addrxbuf_edma); int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, void *buf_addr) { - struct ar9003_rxs *rxsp = (struct ar9003_rxs *) buf_addr; + struct ar9003_rxs *rxsp = buf_addr; unsigned int phyerr; if ((rxsp->status11 & AR_RxDone) == 0) @@ -469,19 +495,20 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, rxs->rs_status = 0; rxs->rs_flags = 0; - rxs->flag = 0; + rxs->enc_flags = 0; + rxs->bw = RATE_INFO_BW_20; rxs->rs_datalen = rxsp->status2 & AR_DataLen; rxs->rs_tstamp = rxsp->status3; /* XXX: Keycache */ rxs->rs_rssi = MS(rxsp->status5, AR_RxRSSICombined); - rxs->rs_rssi_ctl0 = MS(rxsp->status1, AR_RxRSSIAnt00); - rxs->rs_rssi_ctl1 = MS(rxsp->status1, AR_RxRSSIAnt01); - rxs->rs_rssi_ctl2 = MS(rxsp->status1, AR_RxRSSIAnt02); - rxs->rs_rssi_ext0 = MS(rxsp->status5, AR_RxRSSIAnt10); - rxs->rs_rssi_ext1 = MS(rxsp->status5, AR_RxRSSIAnt11); - rxs->rs_rssi_ext2 = MS(rxsp->status5, AR_RxRSSIAnt12); + rxs->rs_rssi_ctl[0] = MS(rxsp->status1, AR_RxRSSIAnt00); + rxs->rs_rssi_ctl[1] = MS(rxsp->status1, AR_RxRSSIAnt01); + rxs->rs_rssi_ctl[2] = MS(rxsp->status1, AR_RxRSSIAnt02); + rxs->rs_rssi_ext[0] = MS(rxsp->status5, AR_RxRSSIAnt10); + rxs->rs_rssi_ext[1] = MS(rxsp->status5, AR_RxRSSIAnt11); + rxs->rs_rssi_ext[2] = MS(rxsp->status5, AR_RxRSSIAnt12); if (rxsp->status11 & AR_RxKeyIdxValid) rxs->rs_keyix = MS(rxsp->status11, AR_KeyIdx); @@ -491,11 +518,14 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, rxs->rs_rate = MS(rxsp->status1, AR_RxRate); rxs->rs_more = (rxsp->status2 & AR_RxMore) ? 1 : 0; + rxs->rs_firstaggr = (rxsp->status11 & AR_RxFirstAggr) ? 1 : 0; rxs->rs_isaggr = (rxsp->status11 & AR_RxAggr) ? 1 : 0; rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0; rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7); - rxs->flag |= (rxsp->status4 & AR_GI) ? RX_FLAG_SHORT_GI : 0; - rxs->flag |= (rxsp->status4 & AR_2040) ? RX_FLAG_40MHZ : 0; + rxs->enc_flags |= (rxsp->status4 & AR_GI) ? RX_ENC_FLAG_SHORT_GI : 0; + rxs->enc_flags |= + (rxsp->status4 & AR_STBC) ? (1 << RX_ENC_FLAG_STBC_SHIFT) : 0; + rxs->bw = (rxsp->status4 & AR_2040) ? RATE_INFO_BW_40 : RATE_INFO_BW_20; rxs->evm0 = rxsp->status6; rxs->evm1 = rxsp->status7; @@ -583,7 +613,7 @@ void ath9k_hw_setup_statusring(struct ath_hw *ah, void *ts_start, ah->ts_paddr_start = ts_paddr_start; ah->ts_paddr_end = ts_paddr_start + (size * sizeof(struct ar9003_txs)); ah->ts_size = size; - ah->ts_ring = (struct ar9003_txs *) ts_start; + ah->ts_ring = ts_start; ath9k_hw_reset_txstatus_ring(ah); } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 8dd069259e7b..3f0543e55d9b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -19,6 +19,7 @@ #include "hw-ops.h" #include "ar9003_phy.h" #include "ar9003_mci.h" +#include "ar9003_aic.h" static void ar9003_mci_reset_req_wakeup(struct ath_hw *ah) { @@ -284,12 +285,12 @@ static void ar9003_mci_prep_interface(struct ath_hw *ah) AR_MCI_INTERRUPT_RX_MSG_CONT_RST); REG_WRITE(ah, AR_MCI_INTERRUPT_RAW, AR_MCI_INTERRUPT_BT_PRI); - if (mci->is_2g) { + if (mci->is_2g && MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { ar9003_mci_send_lna_transfer(ah, true); udelay(5); } - if ((mci->is_2g && !mci->update_2g5g)) { + if (mci->is_2g && !mci->update_2g5g && MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { if (ar9003_mci_wait_for_interrupt(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, AR_MCI_INTERRUPT_RX_MSG_LNA_INFO, @@ -426,25 +427,38 @@ static void ar9003_mci_observation_set_up(struct ath_hw *ah) struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; if (mci->config & ATH_MCI_CONFIG_MCI_OBS_MCI) { - ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA); - ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK); - ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); - ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); + ath9k_hw_gpio_request_out(ah, 3, NULL, + AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_DATA); + ath9k_hw_gpio_request_out(ah, 2, NULL, + AR_GPIO_OUTPUT_MUX_AS_MCI_WLAN_CLK); + ath9k_hw_gpio_request_out(ah, 1, NULL, + AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); + ath9k_hw_gpio_request_out(ah, 0, NULL, + AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_TXRX) { - ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX); - ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX); - ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); - ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); - ath9k_hw_cfg_output(ah, 5, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_gpio_request_out(ah, 3, NULL, + AR_GPIO_OUTPUT_MUX_AS_WL_IN_TX); + ath9k_hw_gpio_request_out(ah, 2, NULL, + AR_GPIO_OUTPUT_MUX_AS_WL_IN_RX); + ath9k_hw_gpio_request_out(ah, 1, NULL, + AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); + ath9k_hw_gpio_request_out(ah, 0, NULL, + AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); + ath9k_hw_gpio_request_out(ah, 5, NULL, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); } else if (mci->config & ATH_MCI_CONFIG_MCI_OBS_BT) { - ath9k_hw_cfg_output(ah, 3, AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); - ath9k_hw_cfg_output(ah, 2, AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); - ath9k_hw_cfg_output(ah, 1, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); - ath9k_hw_cfg_output(ah, 0, AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); + ath9k_hw_gpio_request_out(ah, 3, NULL, + AR_GPIO_OUTPUT_MUX_AS_BT_IN_TX); + ath9k_hw_gpio_request_out(ah, 2, NULL, + AR_GPIO_OUTPUT_MUX_AS_BT_IN_RX); + ath9k_hw_gpio_request_out(ah, 1, NULL, + AR_GPIO_OUTPUT_MUX_AS_MCI_BT_DATA); + ath9k_hw_gpio_request_out(ah, 0, NULL, + AR_GPIO_OUTPUT_MUX_AS_MCI_BT_CLK); } else return; - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL(ah), AR_GPIO_JTAG_DISABLE); REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_DS_JTAG_DISABLE, 1); REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, AR_GLB_WLAN_UART_INTF_EN, 0); @@ -452,12 +466,12 @@ static void ar9003_mci_observation_set_up(struct ath_hw *ah) REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_GPIO_OBS_SEL, 0); REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL, 1); - REG_WRITE(ah, AR_OBS, 0x4b); + REG_WRITE(ah, AR_OBS(ah), 0x4b); REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL1, 0x03); REG_RMW_FIELD(ah, AR_DIAG_SW, AR_DIAG_OBS_PT_SEL2, 0x01); REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_LSB, 0x02); REG_RMW_FIELD(ah, AR_MACMISC, AR_MACMISC_MISC_OBS_BUS_MSB, 0x03); - REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, + REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS(ah), AR_PHY_TEST_CTL_DEBUGPORT_SEL, 0x07); } @@ -571,7 +585,7 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, { struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - u32 *p_gpm = NULL, mismatch = 0, more_data; + u32 *p_gpm = NULL, more_data; u32 offset; u8 recv_type = 0, recv_opcode = 0; bool b_is_bt_cal_done = (gpm_type == MCI_GPM_BT_CAL_DONE); @@ -593,7 +607,7 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, if (!time_out) break; - offset = ar9003_mci_get_next_gpm_offset(ah, false, &more_data); + offset = ar9003_mci_get_next_gpm_offset(ah, &more_data); if (offset == MCI_GPM_INVALID) continue; @@ -623,7 +637,7 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, * same time. Since BT's calibration doesn't happen * that often, we'll let BT completes calibration then * we continue to wait for cal_grant from BT. - * Orginal: Wait BT_CAL_GRANT. + * Original: Wait BT_CAL_GRANT. * New: Receive BT_CAL_REQ -> send WLAN_CAL_GRANT->wait * BT_CAL_DONE -> Wait BT_CAL_GRANT. */ @@ -642,7 +656,6 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, } else { ath_dbg(common, MCI, "MCI GPM subtype not match 0x%x\n", *(p_gpm + 1)); - mismatch++; ar9003_mci_process_gpm_extra(ah, recv_type, recv_opcode, p_gpm); } @@ -657,7 +670,7 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, time_out = 0; while (more_data == MCI_GPM_MORE) { - offset = ar9003_mci_get_next_gpm_offset(ah, false, &more_data); + offset = ar9003_mci_get_next_gpm_offset(ah, &more_data); if (offset == MCI_GPM_INVALID) break; @@ -734,7 +747,7 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, * BT is sleeping. Check if BT wakes up during * WLAN calibration. If BT wakes up during * WLAN calibration, need to go through all - * message exchanges again and recal. + * message exchanges again and recalibrate. */ REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, (AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | @@ -753,9 +766,9 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, 1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT); if (caldata) { - caldata->done_txiqcal_once = false; - caldata->done_txclcal_once = false; - caldata->rtt_done = false; + clear_bit(TXIQCAL_DONE, &caldata->cal_flags); + clear_bit(TXCLCAL_DONE, &caldata->cal_flags); + clear_bit(RTT_DONE, &caldata->cal_flags); } if (!ath9k_hw_init_cal(ah, chan)) @@ -771,8 +784,14 @@ exit: static void ar9003_mci_mute_bt(struct ath_hw *ah) { + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + /* disable all MCI messages */ REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff); + REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff); REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); /* wait pending HW messages to flush out */ @@ -783,9 +802,10 @@ static void ar9003_mci_mute_bt(struct ath_hw *ah) * 1. reset not after resuming from full sleep * 2. before reset MCI RX, to quiet BT and avoid MCI RX misalignment */ - ar9003_mci_send_lna_take(ah, true); - - udelay(5); + if (MCI_ANT_ARCH_PA_LNA_SHARED(mci)) { + ar9003_mci_send_lna_take(ah, true); + udelay(5); + } ar9003_mci_send_sys_sleeping(ah, true); } @@ -821,6 +841,80 @@ static void ar9003_mci_osla_setup(struct ath_hw *ah, bool enable) AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN, 1); } +static void ar9003_mci_stat_setup(struct ath_hw *ah) +{ + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + + if (!AR_SREV_9565(ah)) + return; + + if (mci->config & ATH_MCI_CONFIG_MCI_STAT_DBG) { + REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, + AR_MCI_DBG_CNT_CTRL_ENABLE, 1); + REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, + AR_MCI_DBG_CNT_CTRL_BT_LINKID, + MCI_STAT_ALL_BT_LINKID); + } else { + REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, + AR_MCI_DBG_CNT_CTRL_ENABLE, 0); + } +} + +static void ar9003_mci_set_btcoex_ctrl_9565_1ANT(struct ath_hw *ah) +{ + u32 regval; + + regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | + SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | + SM(1, AR_BTCOEX_CTRL_PA_SHARED) | + SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | + SM(1, AR_BTCOEX_CTRL_NUM_ANTENNAS) | + SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | + SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | + SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | + SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); + + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, + AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x1); + REG_WRITE(ah, AR_BTCOEX_CTRL, regval); +} + +static void ar9003_mci_set_btcoex_ctrl_9565_2ANT(struct ath_hw *ah) +{ + u32 regval; + + regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | + SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | + SM(0, AR_BTCOEX_CTRL_PA_SHARED) | + SM(0, AR_BTCOEX_CTRL_LNA_SHARED) | + SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | + SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | + SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | + SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | + SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); + + REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, + AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x0); + REG_WRITE(ah, AR_BTCOEX_CTRL, regval); +} + +static void ar9003_mci_set_btcoex_ctrl_9462(struct ath_hw *ah) +{ + u32 regval; + + regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | + SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | + SM(1, AR_BTCOEX_CTRL_PA_SHARED) | + SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | + SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | + SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK) | + SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | + SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | + SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); + + REG_WRITE(ah, AR_BTCOEX_CTRL, regval); +} + int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, bool is_full_sleep) { @@ -831,11 +925,6 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, ath_dbg(common, MCI, "MCI Reset (full_sleep = %d, is_2g = %d)\n", is_full_sleep, is_2g); - if (!mci->gpm_addr && !mci->sched_addr) { - ath_err(common, "MCI GPM and schedule buffers are not allocated\n"); - return -ENOMEM; - } - if (REG_READ(ah, AR_BTCOEX_CTRL) == 0xdeadbeef) { ath_err(common, "BTCOEX control register is dead\n"); return -EINVAL; @@ -850,26 +939,17 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, * To avoid MCI state machine be affected by incoming remote MCI msgs, * MCI mode will be enabled later, right before reset the MCI TX and RX. */ - - regval = SM(1, AR_BTCOEX_CTRL_AR9462_MODE) | - SM(1, AR_BTCOEX_CTRL_WBTIMER_EN) | - SM(1, AR_BTCOEX_CTRL_PA_SHARED) | - SM(1, AR_BTCOEX_CTRL_LNA_SHARED) | - SM(0, AR_BTCOEX_CTRL_1_CHAIN_ACK) | - SM(0, AR_BTCOEX_CTRL_1_CHAIN_BCN) | - SM(0, AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); if (AR_SREV_9565(ah)) { - regval |= SM(1, AR_BTCOEX_CTRL_NUM_ANTENNAS) | - SM(1, AR_BTCOEX_CTRL_RX_CHAIN_MASK); - REG_RMW_FIELD(ah, AR_BTCOEX_CTRL2, - AR_BTCOEX_CTRL2_TX_CHAIN_MASK, 0x1); + u8 ant = MS(mci->config, ATH_MCI_CONFIG_ANT_ARCH); + + if (ant == ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_SHARED) + ar9003_mci_set_btcoex_ctrl_9565_1ANT(ah); + else + ar9003_mci_set_btcoex_ctrl_9565_2ANT(ah); } else { - regval |= SM(2, AR_BTCOEX_CTRL_NUM_ANTENNAS) | - SM(3, AR_BTCOEX_CTRL_RX_CHAIN_MASK); + ar9003_mci_set_btcoex_ctrl_9462(ah); } - REG_WRITE(ah, AR_BTCOEX_CTRL, regval); - if (is_2g && !(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) ar9003_mci_osla_setup(ah, true); else @@ -926,26 +1006,32 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX); REG_WRITE(ah, AR_MCI_COMMAND2, regval); - ar9003_mci_get_next_gpm_offset(ah, true, NULL); + /* Init GPM offset after MCI Reset Rx */ + ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET); REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) | SM(0x0000, AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM))); - REG_CLR_BIT(ah, AR_MCI_TX_CTRL, - AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); + if (MCI_ANT_ARCH_PA_LNA_SHARED(mci)) + REG_CLR_BIT(ah, AR_MCI_TX_CTRL, + AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); + else + REG_SET_BIT(ah, AR_MCI_TX_CTRL, + AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); ar9003_mci_observation_set_up(ah); mci->ready = true; ar9003_mci_prep_interface(ah); + ar9003_mci_stat_setup(ah); - if (AR_SREV_9565(ah)) - REG_RMW_FIELD(ah, AR_MCI_DBG_CNT_CTRL, - AR_MCI_DBG_CNT_CTRL_ENABLE, 0); if (en_int) ar9003_mci_enable_interrupt(ah); + if (ath9k_hw_is_aic_enabled(ah)) + ar9003_aic_start_normal(ah); + return 0; } @@ -968,17 +1054,15 @@ void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep) static void ar9003_mci_send_2g5g_status(struct ath_hw *ah, bool wait_done) { struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - u32 new_flags, to_set, to_clear; + u32 to_set, to_clear; if (!mci->update_2g5g || (mci->bt_state == MCI_BT_SLEEP)) return; if (mci->is_2g) { - new_flags = MCI_2G_FLAGS; to_clear = MCI_2G_FLAGS_CLEAR_MASK; to_set = MCI_2G_FLAGS_SET_MASK; } else { - new_flags = MCI_5G_FLAGS; to_clear = MCI_5G_FLAGS_CLEAR_MASK; to_set = MCI_5G_FLAGS_SET_MASK; } @@ -1218,6 +1302,14 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) } value &= AR_BTCOEX_CTRL_MCI_MODE_EN; break; + case MCI_STATE_INIT_GPM_OFFSET: + value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); + + if (value < mci->gpm_len) + mci->gpm_idx = value; + else + mci->gpm_idx = 0; + break; case MCI_STATE_LAST_SCHD_MSG_OFFSET: value = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_LAST_SCHD_MSG_INDEX); @@ -1284,6 +1376,22 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0; mci->need_flush_btinfo = false; break; + case MCI_STATE_AIC_CAL: + if (ath9k_hw_is_aic_enabled(ah)) + value = ar9003_aic_calibration(ah); + break; + case MCI_STATE_AIC_START: + if (ath9k_hw_is_aic_enabled(ah)) + ar9003_aic_start_normal(ah); + break; + case MCI_STATE_AIC_CAL_RESET: + if (ath9k_hw_is_aic_enabled(ah)) + value = ar9003_aic_cal_reset(ah); + break; + case MCI_STATE_AIC_CAL_SINGLE: + if (ath9k_hw_is_aic_enabled(ah)) + value = ar9003_aic_calibration_single(ah); + break; default: break; } @@ -1364,21 +1472,11 @@ void ar9003_mci_check_gpm_offset(struct ath_hw *ah) mci->gpm_idx = 0; } -u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, bool first, u32 *more) +u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, u32 *more) { struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 offset, more_gpm = 0, gpm_ptr; - if (first) { - gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); - - if (gpm_ptr >= mci->gpm_len) - gpm_ptr = 0; - - mci->gpm_idx = gpm_ptr; - return gpm_ptr; - } - /* * This could be useful to avoid new GPM message interrupt which * may lead to spurious interrupt after power sleep, or multiple diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h index 66d7ab9f920d..e288611c12d5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h @@ -92,14 +92,36 @@ enum mci_gpm_coex_bt_update_flags_op { #define ATH_MCI_CONFIG_CLK_DIV 0x00003000 #define ATH_MCI_CONFIG_CLK_DIV_S 12 #define ATH_MCI_CONFIG_DISABLE_TUNING 0x00004000 +#define ATH_MCI_CONFIG_DISABLE_AIC 0x00008000 +#define ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN 0x007f0000 +#define ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN_S 16 +#define ATH_MCI_CONFIG_NO_QUIET_ACK 0x00800000 +#define ATH_MCI_CONFIG_NO_QUIET_ACK_S 23 +#define ATH_MCI_CONFIG_ANT_ARCH 0x07000000 +#define ATH_MCI_CONFIG_ANT_ARCH_S 24 +#define ATH_MCI_CONFIG_FORCE_QUIET_ACK 0x08000000 +#define ATH_MCI_CONFIG_FORCE_QUIET_ACK_S 27 +#define ATH_MCI_CONFIG_FORCE_2CHAIN_ACK 0x10000000 +#define ATH_MCI_CONFIG_MCI_STAT_DBG 0x20000000 #define ATH_MCI_CONFIG_MCI_WEIGHT_DBG 0x40000000 #define ATH_MCI_CONFIG_DISABLE_MCI 0x80000000 #define ATH_MCI_CONFIG_MCI_OBS_MASK (ATH_MCI_CONFIG_MCI_OBS_MCI | \ ATH_MCI_CONFIG_MCI_OBS_TXRX | \ ATH_MCI_CONFIG_MCI_OBS_BT) + #define ATH_MCI_CONFIG_MCI_OBS_GPIO 0x0000002F +#define ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_NON_SHARED 0x00 +#define ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_SHARED 0x01 +#define ATH_MCI_ANT_ARCH_2_ANT_PA_LNA_NON_SHARED 0x02 +#define ATH_MCI_ANT_ARCH_2_ANT_PA_LNA_SHARED 0x03 +#define ATH_MCI_ANT_ARCH_3_ANT 0x04 + +#define MCI_ANT_ARCH_PA_LNA_SHARED(mci) \ + ((MS(mci->config, ATH_MCI_CONFIG_ANT_ARCH) == ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_SHARED) || \ + (MS(mci->config, ATH_MCI_CONFIG_ANT_ARCH) == ATH_MCI_ANT_ARCH_2_ANT_PA_LNA_SHARED)) + enum mci_message_header { /* length of payload */ MCI_LNA_CTRL = 0x10, /* len = 0 */ MCI_CONT_NACK = 0x20, /* len = 0 */ @@ -188,20 +210,55 @@ enum mci_bt_state { MCI_BT_CAL }; +enum mci_ps_state { + MCI_PS_DISABLE, + MCI_PS_ENABLE, + MCI_PS_ENABLE_OFF, + MCI_PS_ENABLE_ON +}; + /* Type of state query */ enum mci_state_type { MCI_STATE_ENABLE, + MCI_STATE_INIT_GPM_OFFSET, + MCI_STATE_CHECK_GPM_OFFSET, + MCI_STATE_NEXT_GPM_OFFSET, + MCI_STATE_LAST_GPM_OFFSET, + MCI_STATE_BT, + MCI_STATE_SET_BT_SLEEP, MCI_STATE_SET_BT_AWAKE, + MCI_STATE_SET_BT_CAL_START, + MCI_STATE_SET_BT_CAL, MCI_STATE_LAST_SCHD_MSG_OFFSET, MCI_STATE_REMOTE_SLEEP, + MCI_STATE_CONT_STATUS, MCI_STATE_RESET_REQ_WAKE, MCI_STATE_SEND_WLAN_COEX_VERSION, + MCI_STATE_SET_BT_COEX_VERSION, + MCI_STATE_SEND_WLAN_CHANNELS, MCI_STATE_SEND_VERSION_QUERY, MCI_STATE_SEND_STATUS_QUERY, + MCI_STATE_NEED_FLUSH_BT_INFO, + MCI_STATE_SET_CONCUR_TX_PRI, MCI_STATE_RECOVER_RX, MCI_STATE_NEED_FTP_STOMP, + MCI_STATE_NEED_TUNING, + MCI_STATE_NEED_STAT_DEBUG, + MCI_STATE_SHARED_CHAIN_CONCUR_TX, + MCI_STATE_AIC_CAL, + MCI_STATE_AIC_START, + MCI_STATE_AIC_CAL_RESET, + MCI_STATE_AIC_CAL_SINGLE, + MCI_STATE_IS_AR9462, + MCI_STATE_IS_AR9565_1ANT, + MCI_STATE_IS_AR9565_2ANT, + MCI_STATE_WLAN_WEAK_SIGNAL, + MCI_STATE_SET_WLAN_PS_STATE, + MCI_STATE_GET_WLAN_PS_STATE, MCI_STATE_DEBUG, - MCI_STATE_NEED_FLUSH_BT_INFO, + MCI_STATE_STAT_DEBUG, + MCI_STATE_ALLOW_FCS, + MCI_STATE_SET_2G_CONTENTION, MCI_STATE_MAX }; @@ -255,7 +312,7 @@ int ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, void ar9003_mci_cleanup(struct ath_hw *ah); void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, u32 *rx_msg_intr); -u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, bool first, u32 *more); +u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, u32 *more); void ar9003_mci_set_bt_version(struct ath_hw *ah, u8 major, u8 minor); void ar9003_mci_send_wlan_channels(struct ath_hw *ah); /* diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index 6343cc91953e..83d993fff695 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -21,7 +21,7 @@ void ar9003_paprd_enable(struct ath_hw *ah, bool val) { struct ath9k_channel *chan = ah->curchan; - struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + bool is2ghz = IS_CHAN_2GHZ(chan); /* * 3 bits for modalHeader5G.papdRateMaskHt20 @@ -36,17 +36,17 @@ void ar9003_paprd_enable(struct ath_hw *ah, bool val) * -- disable PAPRD for lower band 5GHz */ - if (IS_CHAN_5GHZ(chan)) { + if (!is2ghz) { if (chan->channel >= UPPER_5G_SUB_BAND_START) { - if (le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20) + if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz) & BIT(30)) val = false; } else if (chan->channel >= MID_5G_SUB_BAND_START) { - if (le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20) + if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz) & BIT(29)) val = false; } else { - if (le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20) + if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz) & BIT(28)) val = false; } @@ -201,19 +201,19 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) ar9003_paprd_enable(ah, false); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP, 0x30); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE, 1); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE, 1); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE, 0); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE, 0); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah), AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1); if (AR_SREV_9485(ah)) { @@ -229,15 +229,15 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) } } - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2(ah), AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, val); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN, 4); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1); if (AR_SREV_9485(ah) || @@ -246,10 +246,10 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) AR_SREV_9550(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -3); else - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6); val = -10; @@ -257,16 +257,16 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) if (IS_CHAN_2GHZ(ah->curchan) && !AR_SREV_9462(ah) && !AR_SREV_9565(ah)) val = -15; - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE, val); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4(ah), AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA, 0); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4(ah), AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR, 400); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4(ah), AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES, 100); REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_0_B0, @@ -313,7 +313,7 @@ static unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain, int desired_scale, desired_gain = 0; u32 reg_olpc = 0, reg_cl_gain = 0; - REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, + REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); desired_scale = REG_READ_FIELD(ah, AR_PHY_TPC_12, AR_PHY_TPC_12_DESIRED_SCALE_HT40_5); @@ -812,7 +812,7 @@ void ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) ar9003_tx_force_gain(ah, gain_index); - REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, + REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); } EXPORT_SYMBOL(ar9003_paprd_setup_gain_table); @@ -833,7 +833,7 @@ static bool ar9003_paprd_retrain_pa_in(struct ath_hw *ah, capdiv2g = REG_READ_FIELD(ah, AR_PHY_65NM_CH0_TXRF3, AR_PHY_65NM_CH0_TXRF3_CAPDIV2G); - quick_drop = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, + quick_drop = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP); if (quick_drop) @@ -906,7 +906,7 @@ static bool ar9003_paprd_retrain_pa_in(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_TXRF3, AR_PHY_65NM_CH0_TXRF3_CAPDIV2G, capdiv2g); - REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, + REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah), AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, quick_drop); @@ -925,21 +925,21 @@ int ar9003_paprd_create_curve(struct ath_hw *ah, memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain])); - buf = kmalloc(2 * 48 * sizeof(u32), GFP_KERNEL); + buf = kmalloc_array(2 * 48, sizeof(u32), GFP_KERNEL); if (!buf) return -ENOMEM; data_L = &buf[0]; data_U = &buf[48]; - REG_CLR_BIT(ah, AR_PHY_CHAN_INFO_MEMORY, + REG_CLR_BIT(ah, AR_PHY_CHAN_INFO_MEMORY(ah), AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ); reg = AR_PHY_CHAN_INFO_TAB_0; for (i = 0; i < 48; i++) data_L[i] = REG_READ(ah, reg + (i << 2)); - REG_SET_BIT(ah, AR_PHY_CHAN_INFO_MEMORY, + REG_SET_BIT(ah, AR_PHY_CHAN_INFO_MEMORY(ah), AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ); for (i = 0; i < 48; i++) @@ -951,7 +951,7 @@ int ar9003_paprd_create_curve(struct ath_hw *ah, if (ar9003_paprd_retrain_pa_in(ah, caldata, chain)) status = -EINPROGRESS; - REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, + REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); kfree(buf); @@ -977,14 +977,14 @@ bool ar9003_paprd_is_done(struct ath_hw *ah) { int paprd_done, agc2_pwr; - paprd_done = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1, + paprd_done = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); if (AR_SREV_9485(ah)) goto exit; if (paprd_done == 0x1) { - agc2_pwr = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1, + agc2_pwr = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah), AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR); ath_dbg(ath9k_hw_common(ah), CALIBRATE, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 1f694ab3cc78..6274d1624261 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -17,6 +17,22 @@ #include <linux/export.h> #include "hw.h" #include "ar9003_phy.h" +#include "ar9003_eeprom.h" + +#define AR9300_OFDM_RATES 8 +#define AR9300_HT_SS_RATES 8 +#define AR9300_HT_DS_RATES 8 +#define AR9300_HT_TS_RATES 8 + +#define AR9300_11NA_OFDM_SHIFT 0 +#define AR9300_11NA_HT_SS_SHIFT 8 +#define AR9300_11NA_HT_DS_SHIFT 16 +#define AR9300_11NA_HT_TS_SHIFT 24 + +#define AR9300_11NG_OFDM_SHIFT 4 +#define AR9300_11NG_HT_SS_SHIFT 12 +#define AR9300_11NG_HT_DS_SHIFT 20 +#define AR9300_11NG_HT_TS_SHIFT 28 static const int firstep_table[] = /* level: 0 1 2 3 4 5 6 7 8 */ @@ -40,6 +56,71 @@ static const int m2ThreshLowExt_off = 127; static const int m1ThreshExt_off = 127; static const int m2ThreshExt_off = 127; +static const u8 ofdm2pwr[] = { + ALL_TARGET_LEGACY_6_24, + ALL_TARGET_LEGACY_6_24, + ALL_TARGET_LEGACY_6_24, + ALL_TARGET_LEGACY_6_24, + ALL_TARGET_LEGACY_6_24, + ALL_TARGET_LEGACY_36, + ALL_TARGET_LEGACY_48, + ALL_TARGET_LEGACY_54 +}; + +static const u8 mcs2pwr_ht20[] = { + ALL_TARGET_HT20_0_8_16, + ALL_TARGET_HT20_1_3_9_11_17_19, + ALL_TARGET_HT20_1_3_9_11_17_19, + ALL_TARGET_HT20_1_3_9_11_17_19, + ALL_TARGET_HT20_4, + ALL_TARGET_HT20_5, + ALL_TARGET_HT20_6, + ALL_TARGET_HT20_7, + ALL_TARGET_HT20_0_8_16, + ALL_TARGET_HT20_1_3_9_11_17_19, + ALL_TARGET_HT20_1_3_9_11_17_19, + ALL_TARGET_HT20_1_3_9_11_17_19, + ALL_TARGET_HT20_12, + ALL_TARGET_HT20_13, + ALL_TARGET_HT20_14, + ALL_TARGET_HT20_15, + ALL_TARGET_HT20_0_8_16, + ALL_TARGET_HT20_1_3_9_11_17_19, + ALL_TARGET_HT20_1_3_9_11_17_19, + ALL_TARGET_HT20_1_3_9_11_17_19, + ALL_TARGET_HT20_20, + ALL_TARGET_HT20_21, + ALL_TARGET_HT20_22, + ALL_TARGET_HT20_23 +}; + +static const u8 mcs2pwr_ht40[] = { + ALL_TARGET_HT40_0_8_16, + ALL_TARGET_HT40_1_3_9_11_17_19, + ALL_TARGET_HT40_1_3_9_11_17_19, + ALL_TARGET_HT40_1_3_9_11_17_19, + ALL_TARGET_HT40_4, + ALL_TARGET_HT40_5, + ALL_TARGET_HT40_6, + ALL_TARGET_HT40_7, + ALL_TARGET_HT40_0_8_16, + ALL_TARGET_HT40_1_3_9_11_17_19, + ALL_TARGET_HT40_1_3_9_11_17_19, + ALL_TARGET_HT40_1_3_9_11_17_19, + ALL_TARGET_HT40_12, + ALL_TARGET_HT40_13, + ALL_TARGET_HT40_14, + ALL_TARGET_HT40_15, + ALL_TARGET_HT40_0_8_16, + ALL_TARGET_HT40_1_3_9_11_17_19, + ALL_TARGET_HT40_1_3_9_11_17_19, + ALL_TARGET_HT40_1_3_9_11_17_19, + ALL_TARGET_HT40_20, + ALL_TARGET_HT40_21, + ALL_TARGET_HT40_22, + ALL_TARGET_HT40_23, +}; + /** * ar9003_hw_set_channel - set channel on single-chip device * @ah: atheros hardware structure @@ -76,7 +157,9 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) freq = centers.synth_center; if (freq < 4800) { /* 2 GHz, fractional mode */ - if (AR_SREV_9330(ah)) { + if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || + AR_SREV_9531(ah) || AR_SREV_9550(ah) || + AR_SREV_9561(ah) || AR_SREV_9565(ah)) { if (ah->is_clk_25mhz) div = 75; else @@ -85,16 +168,6 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) channelSel = (freq * 4) / div; chan_frac = (((freq * 4) % div) * 0x20000) / div; channelSel = (channelSel << 17) | chan_frac; - } else if (AR_SREV_9485(ah) || AR_SREV_9565(ah)) { - /* - * freq_ref = 40 / (refdiva >> amoderefsel); - * where refdiva=1 and amoderefsel=0 - * ndiv = ((chan_mhz * 4) / 3) / freq_ref; - * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000 - */ - channelSel = (freq * 4) / 120; - chan_frac = (((freq * 4) % 120) * 0x20000) / 120; - channelSel = (channelSel << 17) | chan_frac; } else if (AR_SREV_9340(ah)) { if (ah->is_clk_25mhz) { channelSel = (freq * 2) / 75; @@ -103,22 +176,14 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) } else { channelSel = CHANSEL_2G(freq) >> 1; } - } else if (AR_SREV_9550(ah)) { - if (ah->is_clk_25mhz) - div = 75; - else - div = 120; - - channelSel = (freq * 4) / div; - chan_frac = (((freq * 4) % div) * 0x20000) / div; - channelSel = (channelSel << 17) | chan_frac; } else { channelSel = CHANSEL_2G(freq); } /* Set to 2G mode */ bMode = 1; } else { - if ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) && + if ((AR_SREV_9340(ah) || AR_SREV_9550(ah) || + AR_SREV_9531(ah) || AR_SREV_9561(ah)) && ah->is_clk_25mhz) { channelSel = freq / 75; chan_frac = ((freq % 75) * 0x20000) / 75; @@ -185,7 +250,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, */ if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || - AR_SREV_9550(ah)) { + AR_SREV_9550(ah) || AR_SREV_9561(ah)) { if (spur_fbin_ptr[0] == 0) /* No spur */ return; max_spur_cnts = 5; @@ -212,7 +277,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, negative = 0; if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || - AR_SREV_9550(ah)) + AR_SREV_9550(ah) || AR_SREV_9561(ah)) cur_bb_spur = ath9k_hw_fbin2freq(spur_fbin_ptr[i], IS_CHAN_2GHZ(chan)); else @@ -231,7 +296,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, cck_spur_freq = cck_spur_freq & 0xfffff; - REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL, + REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_YCOK_MAX, 0x7); REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR, 0x7f); @@ -249,7 +314,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, } } - REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL, + REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_YCOK_MAX, 0x5); REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, 0x0); @@ -287,7 +352,7 @@ static void ar9003_hw_spur_ofdm_clear(struct ath_hw *ah) AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0); REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, 0); - REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A, + REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A(ah), AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, 0); REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, 0); @@ -295,7 +360,7 @@ static void ar9003_hw_spur_ofdm_clear(struct ath_hw *ah) AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0); REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0); - REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A, + REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A(ah), AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0); REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0); @@ -354,7 +419,7 @@ static void ar9003_hw_spur_ofdm(struct ath_hw *ah, AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0x1); REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, mask_index); - REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A, + REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A(ah), AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, mask_index); REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, mask_index); @@ -362,7 +427,7 @@ static void ar9003_hw_spur_ofdm(struct ath_hw *ah, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0xc); REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0xc); - REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A, + REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A(ah), AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0xa0); REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0xff); @@ -384,7 +449,7 @@ static void ar9003_hw_spur_ofdm_9565(struct ath_hw *ah, mask_index); /* A == B */ - REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_B, + REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_B(ah), AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, mask_index); @@ -397,7 +462,7 @@ static void ar9003_hw_spur_ofdm_9565(struct ath_hw *ah, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_B, 0xe); /* A == B */ - REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_B, + REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_B(ah), AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0xa0); } @@ -458,21 +523,10 @@ static void ar9003_hw_spur_mitigate_ofdm(struct ath_hw *ah, int synth_freq; int range = 10; int freq_offset = 0; - int mode; - u8* spurChansPtr; + u8 *spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah, IS_CHAN_2GHZ(chan)); unsigned int i; - struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; - if (IS_CHAN_5GHZ(chan)) { - spurChansPtr = &(eep->modalHeader5G.spurChans[0]); - mode = 0; - } - else { - spurChansPtr = &(eep->modalHeader2G.spurChans[0]); - mode = 1; - } - - if (spurChansPtr[0] == 0) + if (spur_fbin_ptr[0] == 0) return; /* No spur in the mode */ if (IS_CHAN_HT40(chan)) { @@ -489,16 +543,18 @@ static void ar9003_hw_spur_mitigate_ofdm(struct ath_hw *ah, ar9003_hw_spur_ofdm_clear(ah); - for (i = 0; i < AR_EEPROM_MODAL_SPURS && spurChansPtr[i]; i++) { - freq_offset = ath9k_hw_fbin2freq(spurChansPtr[i], mode); + for (i = 0; i < AR_EEPROM_MODAL_SPURS && spur_fbin_ptr[i]; i++) { + freq_offset = ath9k_hw_fbin2freq(spur_fbin_ptr[i], + IS_CHAN_2GHZ(chan)); freq_offset -= synth_freq; if (abs(freq_offset) < range) { ar9003_hw_spur_ofdm_work(ah, chan, freq_offset, range, synth_freq); if (AR_SREV_9565(ah) && (i < 4)) { - freq_offset = ath9k_hw_fbin2freq(spurChansPtr[i + 1], - mode); + freq_offset = + ath9k_hw_fbin2freq(spur_fbin_ptr[i + 1], + IS_CHAN_2GHZ(chan)); freq_offset -= synth_freq; if (abs(freq_offset) < range) ar9003_hw_spur_ofdm_9565(ah, freq_offset); @@ -517,6 +573,23 @@ static void ar9003_hw_spur_mitigate(struct ath_hw *ah, ar9003_hw_spur_mitigate_ofdm(ah, chan); } +static u32 ar9003_hw_compute_pll_control_soc(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + u32 pll; + + pll = SM(0x5, AR_RTC_9300_SOC_PLL_REFDIV); + + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_9300_SOC_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_9300_SOC_PLL_CLKSEL); + + pll |= SM(0x2c, AR_RTC_9300_SOC_PLL_DIV_INT); + + return pll; +} + static u32 ar9003_hw_compute_pll_control(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -544,15 +617,16 @@ static void ar9003_hw_set_channel_regs(struct ath_hw *ah, (REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO); /* Enable 11n HT, 20 MHz */ - phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 | - AR_PHY_GC_SHORT_GI_40 | enableDacFifo; + phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SHORT_GI_40 | enableDacFifo; + + if (!AR_SREV_9561(ah)) + phymode |= AR_PHY_GC_SINGLE_HT_LTF1; /* Configure baseband for dynamic 20/40 operation */ if (IS_CHAN_HT40(chan)) { phymode |= AR_PHY_GC_DYN2040_EN; /* Configure control (primary) channel at +-10MHz */ - if ((chan->chanmode == CHANNEL_A_HT40PLUS) || - (chan->chanmode == CHANNEL_G_HT40PLUS)) + if (IS_CHAN_HT40PLUS(chan)) phymode |= AR_PHY_GC_DYN2040_PRI_CH; } @@ -565,7 +639,7 @@ static void ar9003_hw_set_channel_regs(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_GEN_CTRL, phymode); /* Configure MAC for 20/40 operation */ - ath9k_hw_set11nmac2040(ah); + ath9k_hw_set11nmac2040(ah, chan); /* global transmit timeout (25 TUs default)*/ REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); @@ -627,11 +701,41 @@ static void ar9003_hw_override_ini(struct ath_hw *ah) * MAC addr only will fail. */ val = REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE); - REG_WRITE(ah, AR_PCU_MISC_MODE2, - val | AR_AGG_WEP_ENABLE_FIX | AR_AGG_WEP_ENABLE); + val |= AR_AGG_WEP_ENABLE_FIX | + AR_AGG_WEP_ENABLE | + AR_PCU_MISC_MODE2_CFP_IGNORE; + REG_WRITE(ah, AR_PCU_MISC_MODE2, val); + + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { + REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE, + AR_GLB_SWREG_DISCONT_EN_BT_WLAN); - REG_SET_BIT(ah, AR_PHY_CCK_DETECT, - AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); + if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), + AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) + ah->enabled_cals |= TX_IQ_CAL; + else + ah->enabled_cals &= ~TX_IQ_CAL; + + } + + if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) + ah->enabled_cals |= TX_CL_CAL; + else + ah->enabled_cals &= ~TX_CL_CAL; + + if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah) || + AR_SREV_9561(ah)) { + if (ah->is_clk_25mhz) { + REG_WRITE(ah, AR_RTC_DERIVED_CLK(ah), 0x17c << 1); + REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); + REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae); + } else { + REG_WRITE(ah, AR_RTC_DERIVED_CLK(ah), 0x261 << 1); + REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400); + REG_WRITE(ah, AR_SLP32_INC, 0x0001e800); + } + udelay(100); + } } static void ar9003_hw_prog_ini(struct ath_hw *ah, @@ -662,48 +766,90 @@ static void ar9003_hw_prog_ini(struct ath_hw *ah, } } -static int ar9550_hw_get_modes_txgain_index(struct ath_hw *ah, +static u32 ar9550_hw_get_modes_txgain_index(struct ath_hw *ah, struct ath9k_channel *chan) { - int ret; - - switch (chan->chanmode) { - case CHANNEL_A: - case CHANNEL_A_HT20: - if (chan->channel <= 5350) - ret = 1; - else if ((chan->channel > 5350) && (chan->channel <= 5600)) - ret = 3; - else - ret = 5; - break; + u32 ret; - case CHANNEL_A_HT40PLUS: - case CHANNEL_A_HT40MINUS: - if (chan->channel <= 5350) - ret = 2; - else if ((chan->channel > 5350) && (chan->channel <= 5600)) - ret = 4; + if (IS_CHAN_2GHZ(chan)) { + if (IS_CHAN_HT40(chan)) + return 7; else - ret = 6; - break; + return 8; + } - case CHANNEL_G: - case CHANNEL_G_HT20: - case CHANNEL_B: - ret = 8; - break; + if (chan->channel <= 5350) + ret = 1; + else if ((chan->channel > 5350) && (chan->channel <= 5600)) + ret = 3; + else + ret = 5; - case CHANNEL_G_HT40PLUS: - case CHANNEL_G_HT40MINUS: - ret = 7; - break; + if (IS_CHAN_HT40(chan)) + ret++; - default: - ret = -EINVAL; + return ret; +} + +static u32 ar9561_hw_get_modes_txgain_index(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + if (IS_CHAN_2GHZ(chan)) { + if (IS_CHAN_HT40(chan)) + return 1; + else + return 2; } - return ret; + return 0; +} + +static void ar9003_doubler_fix(struct ath_hw *ah) +{ + if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9550(ah)) { + REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, + 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | + 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); + REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, + 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | + 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); + REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, + 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | + 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); + + udelay(200); + + REG_CLR_BIT(ah, AR_PHY_65NM_CH0_RXTX2, + AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); + REG_CLR_BIT(ah, AR_PHY_65NM_CH1_RXTX2, + AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); + REG_CLR_BIT(ah, AR_PHY_65NM_CH2_RXTX2, + AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); + + udelay(1); + + REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX2, + AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); + REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX2, + AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); + REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX2, + AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); + + udelay(200); + + REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_SYNTH12, + AR_PHY_65NM_CH0_SYNTH12_VREFMUL3, 0xf); + + REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 0, + 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | + 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); + REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 0, + 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | + 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); + REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 0, + 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | + 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); + } } static int ar9003_hw_process_ini(struct ath_hw *ah, @@ -712,28 +858,10 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, unsigned int regWrites = 0, i; u32 modesIndex; - switch (chan->chanmode) { - case CHANNEL_A: - case CHANNEL_A_HT20: - modesIndex = 1; - break; - case CHANNEL_A_HT40PLUS: - case CHANNEL_A_HT40MINUS: - modesIndex = 2; - break; - case CHANNEL_G: - case CHANNEL_G_HT20: - case CHANNEL_B: - modesIndex = 4; - break; - case CHANNEL_G_HT40PLUS: - case CHANNEL_G_HT40MINUS: - modesIndex = 3; - break; - - default: - return -EINVAL; - } + if (IS_CHAN_5GHZ(chan)) + modesIndex = IS_CHAN_HT40(chan) ? 2 : 1; + else + modesIndex = IS_CHAN_HT40(chan) ? 3 : 4; /* * SOC, MAC, BB, RADIO initvals. @@ -749,6 +877,8 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, modesIndex); } + ar9003_doubler_fix(ah); + /* * RXGAIN initvals. */ @@ -770,24 +900,30 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, */ if ((ar9003_hw_get_rx_gain_idx(ah) == 2) || (ar9003_hw_get_rx_gain_idx(ah) == 3)) { - REG_WRITE_ARRAY(&ah->ini_modes_rxgain_5g_xlna, + REG_WRITE_ARRAY(&ah->ini_modes_rxgain_xlna, modesIndex, regWrites); } } - if (AR_SREV_9550(ah)) + if (AR_SREV_9550(ah) || AR_SREV_9561(ah)) REG_WRITE_ARRAY(&ah->ini_modes_rx_gain_bounds, modesIndex, regWrites); + if (AR_SREV_9561(ah) && (ar9003_hw_get_rx_gain_idx(ah) == 0)) + REG_WRITE_ARRAY(&ah->ini_modes_rxgain_xlna, + modesIndex, regWrites); /* * TXGAIN initvals. */ - if (AR_SREV_9550(ah)) { - int modes_txgain_index; + if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) { + u32 modes_txgain_index = 1; - modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan); - if (modes_txgain_index < 0) - return -EINVAL; + if (AR_SREV_9550(ah)) + modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan); + + if (AR_SREV_9561(ah)) + modes_txgain_index = + ar9561_hw_get_modes_txgain_index(ah, chan); REG_WRITE_ARRAY(&ah->iniModesTxGain, modes_txgain_index, regWrites); @@ -811,12 +947,13 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, /* * JAPAN regulatory. */ - if (chan->channel == 2484) + if (chan->channel == 2484) { ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1); - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) - REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE, - AR_GLB_SWREG_DISCONT_EN_BT_WLAN); + if (AR_SREV_9531(ah)) + REG_RMW_FIELD(ah, AR_PHY_FCAL_2_0, + AR_PHY_FLC_PWR_THRESH, 0); + } ah->modes_index = modesIndex; ar9003_hw_override_ini(ah); @@ -824,19 +961,6 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); ath9k_hw_apply_txpower(ah, chan, false); - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { - if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0, - AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) - ah->enabled_cals |= TX_IQ_CAL; - else - ah->enabled_cals &= ~TX_IQ_CAL; - - if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) - ah->enabled_cals |= TX_CL_CAL; - else - ah->enabled_cals &= ~TX_CL_CAL; - } - return 0; } @@ -848,17 +972,15 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah, if (chan == NULL) return; - rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) - ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; + if (IS_CHAN_2GHZ(chan)) + rfMode |= AR_PHY_MODE_DYNAMIC; + else + rfMode |= AR_PHY_MODE_OFDM; if (IS_CHAN_A_FAST_CLOCK(ah, chan)) rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); - if (IS_CHAN_QUARTER_RATE(chan)) - rfMode |= AR_PHY_MODE_QUARTER; - if (IS_CHAN_HALF_RATE(chan)) - rfMode |= AR_PHY_MODE_HALF; - if (rfMode & (AR_PHY_MODE_QUARTER | AR_PHY_MODE_HALF)) + if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW, 3); @@ -1173,6 +1295,10 @@ skip_ws_det: * is_on == 0 means MRC CCK is OFF (more noise imm) */ bool is_on = param ? 1 : 0; + + if (ah->caps.rx_chainmask == 1) + break; + REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, AR_PHY_MRC_CCK_ENABLE, is_on); REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, @@ -1182,16 +1308,14 @@ skip_ws_det: chan->channel, aniState->mrcCCK ? "on" : "off", is_on ? "on" : "off"); - if (is_on) - ah->stats.ast_ani_ccklow++; - else - ah->stats.ast_ani_cckhigh++; - aniState->mrcCCK = is_on; + if (is_on) + ah->stats.ast_ani_ccklow++; + else + ah->stats.ast_ani_cckhigh++; + aniState->mrcCCK = is_on; } break; } - case ATH9K_ANI_PRESENT: - break; default: ath_dbg(common, ANI, "invalid cmd %u\n", cmd); return false; @@ -1273,12 +1397,11 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) aniState = &ah->ani; iniDef = &aniState->iniDef; - ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n", + ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz\n", ah->hw_version.macVersion, ah->hw_version.macRev, ah->opmode, - chan->channel, - chan->channelFlags); + chan->channel); val = REG_READ(ah, AR_PHY_SFCORR); iniDef->m1Thresh = MS(val, AR_PHY_SFCORR_M1_THRESH); @@ -1318,7 +1441,8 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) static void ar9003_hw_set_radar_params(struct ath_hw *ah, struct ath_hw_radar_conf *conf) { - u32 radar_0 = 0, radar_1 = 0; + unsigned int regWrites = 0; + u32 radar_0 = 0, radar_1; if (!conf) { REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA); @@ -1332,6 +1456,9 @@ static void ar9003_hw_set_radar_params(struct ath_hw *ah, radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI); radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND); + radar_1 = REG_READ(ah, AR_PHY_RADAR_1); + radar_1 &= ~(AR_PHY_RADAR_1_MAXLEN | AR_PHY_RADAR_1_RELSTEP_THRESH | + AR_PHY_RADAR_1_RELPWR_THRESH); radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI; radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK; radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN); @@ -1344,6 +1471,11 @@ static void ar9003_hw_set_radar_params(struct ath_hw *ah, REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); else REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); + + if (AR_SREV_9300(ah) || AR_SREV_9340(ah) || AR_SREV_9580(ah)) { + REG_WRITE_ARRAY(&ah->ini_dfs, + IS_CHAN_HT40(ah->curchan) ? 2 : 1, regWrites); + } } static void ar9003_hw_set_radar_conf(struct ath_hw *ah) @@ -1353,7 +1485,7 @@ static void ar9003_hw_set_radar_conf(struct ath_hw *ah) conf->fir_power = -28; conf->radar_rssi = 0; conf->pulse_height = 10; - conf->pulse_rssi = 24; + conf->pulse_rssi = 15; conf->pulse_inband = 8; conf->pulse_maxlen = 255; conf->pulse_inband_step = 12; @@ -1374,15 +1506,19 @@ static void ar9003_hw_antdiv_comb_conf_get(struct ath_hw *ah, AR_PHY_ANT_FAST_DIV_BIAS_S; if (AR_SREV_9330_11(ah)) { + antconf->lna1_lna2_switch_delta = -1; antconf->lna1_lna2_delta = -9; antconf->div_group = 1; } else if (AR_SREV_9485(ah)) { + antconf->lna1_lna2_switch_delta = -1; antconf->lna1_lna2_delta = -9; antconf->div_group = 2; } else if (AR_SREV_9565(ah)) { - antconf->lna1_lna2_delta = -3; + antconf->lna1_lna2_switch_delta = 3; + antconf->lna1_lna2_delta = -9; antconf->div_group = 3; } else { + antconf->lna1_lna2_switch_delta = -1; antconf->lna1_lna2_delta = -3; antconf->div_group = 0; } @@ -1413,94 +1549,131 @@ static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); } -static void ar9003_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah, - bool enable) +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + +static void ar9003_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) { + struct ath9k_hw_capabilities *pCap = &ah->caps; u8 ant_div_ctl1; u32 regval; - if (!AR_SREV_9565(ah)) + if (!AR_SREV_9485(ah) && !AR_SREV_9565(ah)) return; - ah->shared_chain_lnadiv = enable; + if (AR_SREV_9485(ah)) { + regval = ar9003_hw_ant_ctrl_common_2_get(ah, + IS_CHAN_2GHZ(ah->curchan)); + if (enable) { + regval &= ~AR_SWITCH_TABLE_COM2_ALL; + regval |= ah->config.ant_ctrl_comm2g_switch_enable; + } + REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, + AR_SWITCH_TABLE_COM2_ALL, regval); + } + ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); + /* + * Set MAIN/ALT LNA conf. + * Set MAIN/ALT gain_tb. + */ regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); regval &= (~AR_ANT_DIV_CTRL_ALL); regval |= (ant_div_ctl1 & 0x3f) << AR_ANT_DIV_CTRL_ALL_S; - regval &= ~AR_PHY_ANT_DIV_LNADIV; - regval |= ((ant_div_ctl1 >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S; - - if (enable) - regval |= AR_ANT_DIV_ENABLE; - REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); - regval = REG_READ(ah, AR_PHY_CCK_DETECT); - regval &= ~AR_FAST_DIV_ENABLE; - regval |= ((ant_div_ctl1 >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S; - - if (enable) - regval |= AR_FAST_DIV_ENABLE; + if (AR_SREV_9485_11_OR_LATER(ah)) { + /* + * Enable LNA diversity. + */ + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + regval &= ~AR_PHY_ANT_DIV_LNADIV; + regval |= ((ant_div_ctl1 >> 6) & 0x1) << AR_PHY_ANT_DIV_LNADIV_S; + if (enable) + regval |= AR_ANT_DIV_ENABLE; - REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); - if (enable) { - REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL, - (1 << AR_PHY_ANT_SW_RX_PROT_S)); - if (ah->curchan && IS_CHAN_2GHZ(ah->curchan)) + /* + * Enable fast antenna diversity. + */ + regval = REG_READ(ah, AR_PHY_CCK_DETECT); + regval &= ~AR_FAST_DIV_ENABLE; + regval |= ((ant_div_ctl1 >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S; + if (enable) + regval |= AR_FAST_DIV_ENABLE; + + REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); + + if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + regval &= (~(AR_PHY_ANT_DIV_MAIN_LNACONF | + AR_PHY_ANT_DIV_ALT_LNACONF | + AR_PHY_ANT_DIV_ALT_GAINTB | + AR_PHY_ANT_DIV_MAIN_GAINTB)); + /* + * Set MAIN to LNA1 and ALT to LNA2 at the + * beginning. + */ + regval |= (ATH_ANT_DIV_COMB_LNA1 << + AR_PHY_ANT_DIV_MAIN_LNACONF_S); + regval |= (ATH_ANT_DIV_COMB_LNA2 << + AR_PHY_ANT_DIV_ALT_LNACONF_S); + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); + } + } else if (AR_SREV_9565(ah)) { + if (enable) { + REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL, + AR_ANT_DIV_ENABLE); + REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL, + (1 << AR_PHY_ANT_SW_RX_PROT_S)); + REG_SET_BIT(ah, AR_PHY_CCK_DETECT, + AR_FAST_DIV_ENABLE); REG_SET_BIT(ah, AR_PHY_RESTART, AR_PHY_RESTART_ENABLE_DIV_M2FLAG); - REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, - AR_BTCOEX_WL_LNADIV_FORCE_ON); - } else { - REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE); - REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, - (1 << AR_PHY_ANT_SW_RX_PROT_S)); - REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE); - REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV, - AR_BTCOEX_WL_LNADIV_FORCE_ON); - - regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); - regval &= ~(AR_PHY_ANT_DIV_MAIN_LNACONF | - AR_PHY_ANT_DIV_ALT_LNACONF | - AR_PHY_ANT_DIV_MAIN_GAINTB | - AR_PHY_ANT_DIV_ALT_GAINTB); - regval |= (AR_PHY_ANT_DIV_LNA1 << AR_PHY_ANT_DIV_MAIN_LNACONF_S); - regval |= (AR_PHY_ANT_DIV_LNA2 << AR_PHY_ANT_DIV_ALT_LNACONF_S); - REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); + REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, + AR_BTCOEX_WL_LNADIV_FORCE_ON); + } else { + REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, + AR_ANT_DIV_ENABLE); + REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, + (1 << AR_PHY_ANT_SW_RX_PROT_S)); + REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, + AR_FAST_DIV_ENABLE); + REG_CLR_BIT(ah, AR_PHY_RESTART, + AR_PHY_RESTART_ENABLE_DIV_M2FLAG); + REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV, + AR_BTCOEX_WL_LNADIV_FORCE_ON); + + regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL); + regval &= ~(AR_PHY_ANT_DIV_MAIN_LNACONF | + AR_PHY_ANT_DIV_ALT_LNACONF | + AR_PHY_ANT_DIV_MAIN_GAINTB | + AR_PHY_ANT_DIV_ALT_GAINTB); + regval |= (ATH_ANT_DIV_COMB_LNA1 << + AR_PHY_ANT_DIV_MAIN_LNACONF_S); + regval |= (ATH_ANT_DIV_COMB_LNA2 << + AR_PHY_ANT_DIV_ALT_LNACONF_S); + REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); + } } } +#endif + static int ar9003_hw_fast_chan_change(struct ath_hw *ah, struct ath9k_channel *chan, u8 *ini_reloaded) { unsigned int regWrites = 0; - u32 modesIndex; + u32 modesIndex, txgain_index; - switch (chan->chanmode) { - case CHANNEL_A: - case CHANNEL_A_HT20: - modesIndex = 1; - break; - case CHANNEL_A_HT40PLUS: - case CHANNEL_A_HT40MINUS: - modesIndex = 2; - break; - case CHANNEL_G: - case CHANNEL_G_HT20: - case CHANNEL_B: - modesIndex = 4; - break; - case CHANNEL_G_HT40PLUS: - case CHANNEL_G_HT40MINUS: - modesIndex = 3; - break; + if (IS_CHAN_5GHZ(chan)) + modesIndex = IS_CHAN_HT40(chan) ? 2 : 1; + else + modesIndex = IS_CHAN_HT40(chan) ? 3 : 4; - default: - return -EINVAL; - } + txgain_index = AR_SREV_9531(ah) ? 1 : modesIndex; if (modesIndex == ah->modes_index) { *ini_reloaded = false; @@ -1516,7 +1689,19 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah, ar9003_hw_prog_ini(ah, &ah->ini_radio_post_sys2ant, modesIndex); - REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); + REG_WRITE_ARRAY(&ah->iniModesTxGain, txgain_index, regWrites); + + if (AR_SREV_9462_20_OR_LATER(ah)) { + /* + * CUS217 mix LNA mode. + */ + if (ar9003_hw_get_rx_gain_idx(ah) == 2) { + REG_WRITE_ARRAY(&ah->ini_modes_rxgain_bb_core, + 1, regWrites); + REG_WRITE_ARRAY(&ah->ini_modes_rxgain_bb_postamble, + modesIndex, regWrites); + } + } /* * For 5GHz channels requiring Fast Clock, apply @@ -1528,7 +1713,11 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah, if (AR_SREV_9565(ah)) REG_WRITE_ARRAY(&ah->iniModesFastClock, 1, regWrites); - REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites); + /* + * JAPAN regulatory. + */ + if (chan->channel == 2484) + ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1); ah->modes_index = modesIndex; *ini_reloaded = true; @@ -1552,7 +1741,7 @@ static void ar9003_hw_spectral_scan_config(struct ath_hw *ah, REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA); REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE); - /* on AR93xx and newer, count = 0 will make the the chip send + /* on AR93xx and newer, count = 0 will make the chip send * spectral samples endlessly. Check if this really was intended, * and fix otherwise. */ @@ -1581,6 +1770,8 @@ static void ar9003_hw_spectral_scan_config(struct ath_hw *ah, static void ar9003_hw_spectral_scan_trigger(struct ath_hw *ah) { + REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, + AR_PHY_SPECTRAL_SCAN_ENABLE); /* Activate spectral scan */ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ACTIVE); @@ -1599,6 +1790,131 @@ static void ar9003_hw_spectral_scan_wait(struct ath_hw *ah) } } +static void ar9003_hw_tx99_start(struct ath_hw *ah, u32 qnum) +{ + REG_SET_BIT(ah, AR_PHY_TEST(ah), PHY_AGC_CLR); + REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); + REG_WRITE(ah, AR_CR, AR_CR_RXD); + REG_WRITE(ah, AR_DLCL_IFS(qnum), 0); + REG_WRITE(ah, AR_D_GBL_IFS_SIFS, 20); /* 50 OK */ + REG_WRITE(ah, AR_D_GBL_IFS_EIFS, 20); + REG_WRITE(ah, AR_TIME_OUT, 0x00000400); + REG_WRITE(ah, AR_DRETRY_LIMIT(qnum), 0xffffffff); + REG_SET_BIT(ah, AR_QMISC(qnum), AR_Q_MISC_DCU_EARLY_TERM_REQ); +} + +static void ar9003_hw_tx99_stop(struct ath_hw *ah) +{ + REG_CLR_BIT(ah, AR_PHY_TEST(ah), PHY_AGC_CLR); + REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); +} + +static void ar9003_hw_tx99_set_txpower(struct ath_hw *ah, u8 txpower) +{ + static u8 p_pwr_array[ar9300RateSize] = { 0 }; + unsigned int i; + + txpower = txpower <= MAX_RATE_POWER ? txpower : MAX_RATE_POWER; + for (i = 0; i < ar9300RateSize; i++) + p_pwr_array[i] = txpower; + + ar9003_hw_tx_power_regwrite(ah, p_pwr_array); +} + +static void ar9003_hw_init_txpower_cck(struct ath_hw *ah, u8 *rate_array) +{ + ah->tx_power[0] = rate_array[ALL_TARGET_LEGACY_1L_5L]; + ah->tx_power[1] = rate_array[ALL_TARGET_LEGACY_1L_5L]; + ah->tx_power[2] = min(rate_array[ALL_TARGET_LEGACY_1L_5L], + rate_array[ALL_TARGET_LEGACY_5S]); + ah->tx_power[3] = min(rate_array[ALL_TARGET_LEGACY_11L], + rate_array[ALL_TARGET_LEGACY_11S]); +} + +static void ar9003_hw_init_txpower_ofdm(struct ath_hw *ah, u8 *rate_array, + int offset) +{ + int i, j; + + for (i = offset; i < offset + AR9300_OFDM_RATES; i++) { + /* OFDM rate to power table idx */ + j = ofdm2pwr[i - offset]; + ah->tx_power[i] = rate_array[j]; + } +} + +static void ar9003_hw_init_txpower_ht(struct ath_hw *ah, u8 *rate_array, + int ss_offset, int ds_offset, + int ts_offset, bool is_40) +{ + int i, j, mcs_idx = 0; + const u8 *mcs2pwr = (is_40) ? mcs2pwr_ht40 : mcs2pwr_ht20; + + for (i = ss_offset; i < ss_offset + AR9300_HT_SS_RATES; i++) { + j = mcs2pwr[mcs_idx]; + ah->tx_power[i] = rate_array[j]; + mcs_idx++; + } + + for (i = ds_offset; i < ds_offset + AR9300_HT_DS_RATES; i++) { + j = mcs2pwr[mcs_idx]; + ah->tx_power[i] = rate_array[j]; + mcs_idx++; + } + + for (i = ts_offset; i < ts_offset + AR9300_HT_TS_RATES; i++) { + j = mcs2pwr[mcs_idx]; + ah->tx_power[i] = rate_array[j]; + mcs_idx++; + } +} + +static void ar9003_hw_init_txpower_stbc(struct ath_hw *ah, int ss_offset, + int ds_offset, int ts_offset) +{ + memcpy(&ah->tx_power_stbc[ss_offset], &ah->tx_power[ss_offset], + AR9300_HT_SS_RATES); + memcpy(&ah->tx_power_stbc[ds_offset], &ah->tx_power[ds_offset], + AR9300_HT_DS_RATES); + memcpy(&ah->tx_power_stbc[ts_offset], &ah->tx_power[ts_offset], + AR9300_HT_TS_RATES); +} + +void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array, + struct ath9k_channel *chan) +{ + if (IS_CHAN_5GHZ(chan)) { + ar9003_hw_init_txpower_ofdm(ah, rate_array, + AR9300_11NA_OFDM_SHIFT); + if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) { + ar9003_hw_init_txpower_ht(ah, rate_array, + AR9300_11NA_HT_SS_SHIFT, + AR9300_11NA_HT_DS_SHIFT, + AR9300_11NA_HT_TS_SHIFT, + IS_CHAN_HT40(chan)); + ar9003_hw_init_txpower_stbc(ah, + AR9300_11NA_HT_SS_SHIFT, + AR9300_11NA_HT_DS_SHIFT, + AR9300_11NA_HT_TS_SHIFT); + } + } else { + ar9003_hw_init_txpower_cck(ah, rate_array); + ar9003_hw_init_txpower_ofdm(ah, rate_array, + AR9300_11NG_OFDM_SHIFT); + if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) { + ar9003_hw_init_txpower_ht(ah, rate_array, + AR9300_11NG_HT_SS_SHIFT, + AR9300_11NG_HT_DS_SHIFT, + AR9300_11NG_HT_TS_SHIFT, + IS_CHAN_HT40(chan)); + ar9003_hw_init_txpower_stbc(ah, + AR9300_11NG_HT_SS_SHIFT, + AR9300_11NG_HT_DS_SHIFT, + AR9300_11NG_HT_TS_SHIFT); + } + } +} + void ar9003_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); @@ -1614,7 +1930,13 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) priv_ops->rf_set_freq = ar9003_hw_set_channel; priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate; - priv_ops->compute_pll_control = ar9003_hw_compute_pll_control; + + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) + priv_ops->compute_pll_control = ar9003_hw_compute_pll_control_soc; + else + priv_ops->compute_pll_control = ar9003_hw_compute_pll_control; + priv_ops->set_channel_regs = ar9003_hw_set_channel_regs; priv_ops->init_bb = ar9003_hw_init_bb; priv_ops->process_ini = ar9003_hw_process_ini; @@ -1631,16 +1953,85 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; - ops->antctrl_shared_chain_lnadiv = ar9003_hw_antctrl_shared_chain_lnadiv; ops->spectral_scan_config = ar9003_hw_spectral_scan_config; ops->spectral_scan_trigger = ar9003_hw_spectral_scan_trigger; ops->spectral_scan_wait = ar9003_hw_spectral_scan_wait; +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + ops->set_bt_ant_diversity = ar9003_hw_set_bt_ant_diversity; +#endif + ops->tx99_start = ar9003_hw_tx99_start; + ops->tx99_stop = ar9003_hw_tx99_stop; + ops->tx99_set_txpower = ar9003_hw_tx99_set_txpower; + ar9003_hw_set_nf_limits(ah); ar9003_hw_set_radar_conf(ah); memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs)); } +/* + * Baseband Watchdog signatures: + * + * 0x04000539: BB hang when operating in HT40 DFS Channel. + * Full chip reset is not required, but a recovery + * mechanism is needed. + * + * 0x1300000a: Related to CAC deafness. + * Chip reset is not required. + * + * 0x0400000a: Related to CAC deafness. + * Full chip reset is required. + * + * 0x04000b09: RX state machine gets into an illegal state + * when a packet with unsupported rate is received. + * Full chip reset is required and PHY_RESTART has + * to be disabled. + * + * 0x04000409: Packet stuck on receive. + * Full chip reset is required for all chips except + * AR9340, AR9531 and AR9561. + */ + +/* + * ar9003_hw_bb_watchdog_check(): Returns true if a chip reset is required. + */ +bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah) +{ + u32 val; + + switch(ah->bb_watchdog_last_status) { + case 0x04000539: + val = REG_READ(ah, AR_PHY_RADAR_0); + val &= (~AR_PHY_RADAR_0_FIRPWR); + val |= SM(0x7f, AR_PHY_RADAR_0_FIRPWR); + REG_WRITE(ah, AR_PHY_RADAR_0, val); + udelay(1); + val = REG_READ(ah, AR_PHY_RADAR_0); + val &= ~AR_PHY_RADAR_0_FIRPWR; + val |= SM(AR9300_DFS_FIRPWR, AR_PHY_RADAR_0_FIRPWR); + REG_WRITE(ah, AR_PHY_RADAR_0, val); + + return false; + case 0x1300000a: + return false; + case 0x0400000a: + case 0x04000b09: + return true; + case 0x04000409: + if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) + return false; + else + return true; + default: + /* + * For any other unknown signatures, do a + * full chip reset. + */ + return true; + } +} +EXPORT_SYMBOL(ar9003_hw_bb_watchdog_check); + void ar9003_hw_bb_watchdog_config(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -1757,6 +2148,7 @@ EXPORT_SYMBOL(ar9003_hw_bb_watchdog_dbg_info); void ar9003_hw_disable_phy_restart(struct ath_hw *ah) { + u8 result; u32 val; /* While receiving unsupported rate frame rx state machine @@ -1764,15 +2156,13 @@ void ar9003_hw_disable_phy_restart(struct ath_hw *ah) * state, BB would go hang. If RXSM is in 0xb state after * first bb panic, ensure to disable the phy_restart. */ - if (!((MS(ah->bb_watchdog_last_status, - AR_PHY_WATCHDOG_RX_OFDM_SM) == 0xb) || - ah->bb_hang_rx_ofdm)) - return; - - ah->bb_hang_rx_ofdm = true; - val = REG_READ(ah, AR_PHY_RESTART); - val &= ~AR_PHY_RESTART_ENA; + result = MS(ah->bb_watchdog_last_status, AR_PHY_WATCHDOG_RX_OFDM_SM); - REG_WRITE(ah, AR_PHY_RESTART, val); + if ((result == 0xb) || ah->bb_hang_rx_ofdm) { + ah->bb_hang_rx_ofdm = true; + val = REG_READ(ah, AR_PHY_RESTART); + val &= ~AR_PHY_RESTART_ENA; + REG_WRITE(ah, AR_PHY_RESTART, val); + } } EXPORT_SYMBOL(ar9003_hw_disable_phy_restart); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index d4d39f305a0b..e13873fb8e2f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -148,6 +148,8 @@ #define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S 28 #define AR_PHY_EXT_CCA_THRESH62 0x007F0000 #define AR_PHY_EXT_CCA_THRESH62_S 16 +#define AR_PHY_EXTCHN_PWRTHR1_ANT_DIV_ALT_ANT_MINGAINIDX 0x0000FF00 +#define AR_PHY_EXTCHN_PWRTHR1_ANT_DIV_ALT_ANT_MINGAINIDX_S 8 #define AR_PHY_EXT_MINCCA_PWR 0x01FF0000 #define AR_PHY_EXT_MINCCA_PWR_S 16 #define AR_PHY_EXT_CYCPWR_THR1 0x0000FE00L @@ -244,7 +246,7 @@ /* - * MRC Feild Definitions + * MRC Field Definitions */ #define AR_PHY_SGI_DSC_MAN 0x0007FFF0 #define AR_PHY_SGI_DSC_MAN_S 4 @@ -268,7 +270,7 @@ #define AR_PHY_AGC (AR_AGC_BASE + 0x14) #define AR_PHY_EXT_ATTEN_CTL_0 (AR_AGC_BASE + 0x18) #define AR_PHY_CCA_0 (AR_AGC_BASE + 0x1c) -#define AR_PHY_EXT_CCA0 (AR_AGC_BASE + 0x20) +#define AR_PHY_CCA_CTRL_0 (AR_AGC_BASE + 0x20) #define AR_PHY_RESTART (AR_AGC_BASE + 0x24) /* @@ -296,11 +298,6 @@ #define AR_PHY_ANT_DIV_MAIN_GAINTB 0x40000000 #define AR_PHY_ANT_DIV_MAIN_GAINTB_S 30 -#define AR_PHY_ANT_DIV_LNA1_MINUS_LNA2 0x0 -#define AR_PHY_ANT_DIV_LNA2 0x1 -#define AR_PHY_ANT_DIV_LNA1 0x2 -#define AR_PHY_ANT_DIV_LNA1_PLUS_LNA2 0x3 - #define AR_PHY_EXTCHN_PWRTHR1 (AR_AGC_BASE + 0x2c) #define AR_PHY_EXT_CHN_WIN (AR_AGC_BASE + 0x30) #define AR_PHY_20_40_DET_THR (AR_AGC_BASE + 0x34) @@ -341,13 +338,17 @@ #define AR_PHY_CCA_NOM_VAL_9300_5GHZ -115 #define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ -125 #define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ -125 -#define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ -95 -#define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ -100 +#define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ -60 +#define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ -60 +#define AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_2GHZ -95 +#define AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_5GHZ -100 #define AR_PHY_CCA_NOM_VAL_9462_2GHZ -127 #define AR_PHY_CCA_MIN_GOOD_VAL_9462_2GHZ -127 +#define AR_PHY_CCA_MAX_GOOD_VAL_9462_2GHZ -60 #define AR_PHY_CCA_NOM_VAL_9462_5GHZ -127 #define AR_PHY_CCA_MIN_GOOD_VAL_9462_5GHZ -127 +#define AR_PHY_CCA_MAX_GOOD_VAL_9462_5GHZ -60 #define AR_PHY_CCA_NOM_VAL_9330_2GHZ -118 @@ -396,6 +397,8 @@ #define AR9280_PHY_CCA_THRESH62_S 12 #define AR_PHY_EXT_CCA0_THRESH62 0x000000FF #define AR_PHY_EXT_CCA0_THRESH62_S 0 +#define AR_PHY_EXT_CCA0_THRESH62_1 0x000001FF +#define AR_PHY_EXT_CCA0_THRESH62_1_S 0 #define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003F #define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S 0 #define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0 @@ -451,8 +454,8 @@ #define AR_PHY_GEN_CTRL (AR_SM_BASE + 0x4) #define AR_PHY_MODE (AR_SM_BASE + 0x8) #define AR_PHY_ACTIVE (AR_SM_BASE + 0xc) -#define AR_PHY_SPUR_MASK_A (AR_SM_BASE + 0x20) -#define AR_PHY_SPUR_MASK_B (AR_SM_BASE + 0x24) +#define AR_PHY_SPUR_MASK_A(_ah) (AR_SM_BASE + (AR_SREV_9561(_ah) ? 0x18 : 0x20)) +#define AR_PHY_SPUR_MASK_B(_ah) (AR_SM_BASE + (AR_SREV_9561(_ah) ? 0x1c : 0x24)) #define AR_PHY_SPECTRAL_SCAN (AR_SM_BASE + 0x28) #define AR_PHY_RADAR_BW_FILTER (AR_SM_BASE + 0x2c) #define AR_PHY_SEARCH_START_DELAY (AR_SM_BASE + 0x30) @@ -484,6 +487,9 @@ #define AR_PHY_ADDAC_PARA_CTL (AR_SM_BASE + 0x150) #define AR_PHY_XPA_CFG (AR_SM_BASE + 0x158) +#define AR_PHY_FLC_PWR_THRESH 7 +#define AR_PHY_FLC_PWR_THRESH_S 0 + #define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW 3 #define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW_S 0 @@ -492,7 +498,7 @@ #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A 0x3FF #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A_S 0 -#define AR_PHY_TEST (AR_SM_BASE + 0x160) +#define AR_PHY_TEST(_ah) (AR_SM_BASE + (AR_SREV_9561(_ah) ? 0x15c : 0x160)) #define AR_PHY_TEST_BBB_OBS_SEL 0x780000 #define AR_PHY_TEST_BBB_OBS_SEL_S 19 @@ -503,7 +509,7 @@ #define AR_PHY_TEST_CHAIN_SEL 0xC0000000 #define AR_PHY_TEST_CHAIN_SEL_S 30 -#define AR_PHY_TEST_CTL_STATUS (AR_SM_BASE + 0x164) +#define AR_PHY_TEST_CTL_STATUS(_ah) (AR_SM_BASE + (AR_SREV_9561(_ah) ? 0x160 : 0x164)) #define AR_PHY_TEST_CTL_TSTDAC_EN 0x1 #define AR_PHY_TEST_CTL_TSTDAC_EN_S 0 #define AR_PHY_TEST_CTL_TX_OBS_SEL 0x1C @@ -518,24 +524,29 @@ #define AR_PHY_TEST_CTL_DEBUGPORT_SEL_S 29 -#define AR_PHY_TSTDAC (AR_SM_BASE + 0x168) +#define AR_PHY_TSTDAC(_ah) (AR_SM_BASE + (AR_SREV_9561(_ah) ? 0x164 : 0x168)) -#define AR_PHY_CHAN_STATUS (AR_SM_BASE + 0x16c) +#define AR_PHY_CHAN_STATUS(_ah) (AR_SM_BASE + (AR_SREV_9561(_ah) ? 0x168 : 0x16c)) -#define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + 0x170) +#define AR_PHY_CHAN_INFO_MEMORY(_ah) (AR_SM_BASE + (AR_SREV_9561(_ah) ? 0x16c : 0x170)) #define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ 0x00000008 #define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ_S 3 -#define AR_PHY_CHNINFO_NOISEPWR (AR_SM_BASE + 0x174) -#define AR_PHY_CHNINFO_GAINDIFF (AR_SM_BASE + 0x178) -#define AR_PHY_CHNINFO_FINETIM (AR_SM_BASE + 0x17c) -#define AR_PHY_CHAN_INFO_GAIN_0 (AR_SM_BASE + 0x180) -#define AR_PHY_SCRAMBLER_SEED (AR_SM_BASE + 0x190) -#define AR_PHY_CCK_TX_CTRL (AR_SM_BASE + 0x194) +#define AR_PHY_CHNINFO_NOISEPWR(_ah) (AR_SM_BASE + (AR_SREV_9561(_ah) ? 0x170 : 0x174)) +#define AR_PHY_CHNINFO_GAINDIFF(_ah) (AR_SM_BASE + (AR_SREV_9561(_ah) ? 0x174 : 0x178)) +#define AR_PHY_CHNINFO_FINETIM(_ah) (AR_SM_BASE + (AR_SREV_9561(_ah) ? 0x178 : 0x17c)) +#define AR_PHY_CHAN_INFO_GAIN_0(_ah) (AR_SM_BASE + (AR_SREV_9561(_ah) ? 0x17c : 0x180)) +#define AR_PHY_SCRAMBLER_SEED(_ah) (AR_SM_BASE + (AR_SREV_9561(_ah) ? 0x184 : 0x190)) +#define AR_PHY_CCK_TX_CTRL(_ah) (AR_SM_BASE + (AR_SREV_9561(_ah) ? 0x188 : 0x194)) -#define AR_PHY_HEAVYCLIP_CTL (AR_SM_BASE + 0x1a4) +#define AR_PHY_HEAVYCLIP_CTL(_ah) (AR_SM_BASE + (AR_SREV_9561(_ah) ? 0x198 : 0x1a4)) #define AR_PHY_HEAVYCLIP_20 (AR_SM_BASE + 0x1a8) #define AR_PHY_HEAVYCLIP_40 (AR_SM_BASE + 0x1ac) +#define AR_PHY_HEAVYCLIP_1 (AR_SM_BASE + 0x19c) +#define AR_PHY_HEAVYCLIP_2 (AR_SM_BASE + 0x1a0) +#define AR_PHY_HEAVYCLIP_3 (AR_SM_BASE + 0x1a4) +#define AR_PHY_HEAVYCLIP_4 (AR_SM_BASE + 0x1a8) +#define AR_PHY_HEAVYCLIP_5 (AR_SM_BASE + 0x1ac) #define AR_PHY_ILLEGAL_TXRATE (AR_SM_BASE + 0x1b0) #define AR_PHY_POWER_TX_RATE(_d) (AR_SM_BASE + 0x1c0 + ((_d) << 2)) @@ -600,16 +611,16 @@ #define AR_PHY_TXGAIN_TABLE (AR_SM_BASE + 0x300) -#define AR_PHY_TX_IQCAL_CONTROL_0 (AR_SM_BASE + (AR_SREV_9485(ah) ? \ +#define AR_PHY_TX_IQCAL_CONTROL_0(_ah) (AR_SM_BASE + (AR_SREV_9485(_ah) ? \ 0x3c4 : 0x444)) -#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + (AR_SREV_9485(ah) ? \ +#define AR_PHY_TX_IQCAL_CONTROL_1(_ah) (AR_SM_BASE + (AR_SREV_9485(_ah) ? \ 0x3c8 : 0x448)) -#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + (AR_SREV_9485(ah) ? \ +#define AR_PHY_TX_IQCAL_START(_ah) (AR_SM_BASE + (AR_SREV_9485(_ah) ? \ 0x3c4 : 0x440)) -#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + (AR_SREV_9485(ah) ? \ +#define AR_PHY_TX_IQCAL_STATUS_B0(_ah) (AR_SM_BASE + (AR_SREV_9485(_ah) ? \ 0x3f0 : 0x48c)) -#define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i) (AR_SM_BASE + \ - (AR_SREV_9485(ah) ? \ +#define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_ah, _i) (AR_SM_BASE + \ + (AR_SREV_9485(_ah) ? \ 0x3d0 : 0x450) + ((_i) << 2)) #define AR_PHY_RTT_CTRL (AR_SM_BASE + 0x380) @@ -637,16 +648,6 @@ #define AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE 0x0000ff00 #define AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE_S 8 -/* AIC Registers */ -#define AR_PHY_AIC_CTRL_0_B0 (AR_SM_BASE + 0x4b0) -#define AR_PHY_AIC_CTRL_1_B0 (AR_SM_BASE + 0x4b4) -#define AR_PHY_AIC_CTRL_2_B0 (AR_SM_BASE + 0x4b8) -#define AR_PHY_AIC_CTRL_3_B0 (AR_SM_BASE + 0x4bc) -#define AR_PHY_AIC_STAT_0_B0 (AR_SM_BASE + 0x4c4)) -#define AR_PHY_AIC_STAT_1_B0 (AR_SM_BASE + 0x4c8)) -#define AR_PHY_AIC_CTRL_4_B0 (AR_SM_BASE + 0x4c0) -#define AR_PHY_AIC_STAT_2_B0 (AR_SM_BASE + 0x4cc) - #define AR_PHY_65NM_CH0_TXRF3 0x16048 #define AR_PHY_65NM_CH0_TXRF3_CAPDIV2G 0x0000001e #define AR_PHY_65NM_CH0_TXRF3_CAPDIV2G_S 1 @@ -655,25 +656,39 @@ #define AR_PHY_SYNTH4_LONG_SHIFT_SELECT ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x00000001 : 0x00000002) #define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0 : 1) #define AR_PHY_65NM_CH0_SYNTH7 0x16098 +#define AR_PHY_65NM_CH0_SYNTH12 0x160ac #define AR_PHY_65NM_CH0_BIAS1 0x160c0 #define AR_PHY_65NM_CH0_BIAS2 0x160c4 #define AR_PHY_65NM_CH0_BIAS4 0x160cc +#define AR_PHY_65NM_CH0_RXTX2 0x16104 +#define AR_PHY_65NM_CH1_RXTX2 0x16504 +#define AR_PHY_65NM_CH2_RXTX2 0x16904 #define AR_PHY_65NM_CH0_RXTX4 0x1610c #define AR_PHY_65NM_CH1_RXTX4 0x1650c #define AR_PHY_65NM_CH2_RXTX4 0x1690c -#define AR_CH0_TOP (AR_SREV_9300(ah) ? 0x16288 : \ - (((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x1628c : 0x16280))) +#define AR_PHY_65NM_CH0_BB1 0x16140 +#define AR_PHY_65NM_CH0_BB2 0x16144 +#define AR_PHY_65NM_CH0_BB3 0x16148 +#define AR_PHY_65NM_CH1_BB1 0x16540 +#define AR_PHY_65NM_CH1_BB2 0x16544 +#define AR_PHY_65NM_CH1_BB3 0x16548 +#define AR_PHY_65NM_CH2_BB1 0x16940 +#define AR_PHY_65NM_CH2_BB2 0x16944 +#define AR_PHY_65NM_CH2_BB3 0x16948 + +#define AR_PHY_65NM_CH0_SYNTH12_VREFMUL3 0x00780000 +#define AR_PHY_65NM_CH0_SYNTH12_VREFMUL3_S 19 +#define AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK 0x00000004 +#define AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S 2 +#define AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK 0x00000008 +#define AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S 3 + +#define AR_CH0_TOP(_ah) (AR_SREV_9300(_ah) ? 0x16288 : \ + (((AR_SREV_9462(_ah) || AR_SREV_9565(_ah)) ? 0x1628c : 0x16280))) #define AR_CH0_TOP_XPABIASLVL (AR_SREV_9550(ah) ? 0x3c0 : 0x300) #define AR_CH0_TOP_XPABIASLVL_S (AR_SREV_9550(ah) ? 6 : 8) -#define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : \ - ((AR_SREV_9485(ah) ? 0x1628c : 0x16294))) -#define AR_CH0_THERM_XPABIASLVL_MSB 0x3 -#define AR_CH0_THERM_XPABIASLVL_MSB_S 0 -#define AR_CH0_THERM_XPASHORT2GND 0x4 -#define AR_CH0_THERM_XPASHORT2GND_S 2 - #define AR_SWITCH_TABLE_COM_ALL (0xffff) #define AR_SWITCH_TABLE_COM_ALL_S (0) #define AR_SWITCH_TABLE_COM_AR9462_ALL (0xffffff) @@ -690,33 +705,38 @@ #define AR_SWITCH_TABLE_ALL (0xfff) #define AR_SWITCH_TABLE_ALL_S (0) -#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\ - ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16294 : 0x1628c)) +#define AR_CH0_THERM(_ah) (AR_SREV_9300(_ah) ? 0x16290 :\ + ((AR_SREV_9462(_ah) || AR_SREV_9565(_ah)) ? 0x16294 : 0x1628c)) +#define AR_CH0_THERM_XPABIASLVL_MSB 0x3 +#define AR_CH0_THERM_XPABIASLVL_MSB_S 0 +#define AR_CH0_THERM_XPASHORT2GND 0x4 +#define AR_CH0_THERM_XPASHORT2GND_S 2 -#define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000 -#define AR_PHY_65NM_CH0_THERM_LOCAL_S 31 -#define AR_PHY_65NM_CH0_THERM_START 0x20000000 -#define AR_PHY_65NM_CH0_THERM_START_S 29 -#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT 0x0000ff00 -#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT_S 8 +#define AR_CH0_THERM_LOCAL 0x80000000 +#define AR_CH0_THERM_START 0x20000000 +#define AR_CH0_THERM_SAR_ADC_OUT 0x0000ff00 +#define AR_CH0_THERM_SAR_ADC_OUT_S 8 -#define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \ - (AR_SREV_9462(ah) ? 0x16290 : 0x16284)) -#define AR_CH0_TOP2_XPABIASLVL 0xf000 -#define AR_CH0_TOP2_XPABIASLVL_S 12 +#define AR_CH0_TOP2(_ah) (AR_SREV_9300(_ah) ? 0x1628c : \ + (AR_SREV_9462(_ah) ? 0x16290 : 0x16284)) +#define AR_CH0_TOP2_XPABIASLVL (AR_SREV_9561(ah) ? 0x1e00 : 0xf000) +#define AR_CH0_TOP2_XPABIASLVL_S (AR_SREV_9561(ah) ? 9 : 12) -#define AR_CH0_XTAL (AR_SREV_9300(ah) ? 0x16294 : \ - ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16298 : 0x16290)) +#define AR_CH0_XTAL(_ah) (AR_SREV_9300(_ah) ? 0x16294 : \ + ((AR_SREV_9462(_ah) || AR_SREV_9565(_ah)) ? 0x16298 : \ + (AR_SREV_9561(_ah) ? 0x162c0 : 0x16290))) #define AR_CH0_XTAL_CAPINDAC 0x7f000000 #define AR_CH0_XTAL_CAPINDAC_S 24 #define AR_CH0_XTAL_CAPOUTDAC 0x00fe0000 #define AR_CH0_XTAL_CAPOUTDAC_S 17 -#define AR_PHY_PMU1 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16340 : 0x16c40) +#define AR_PHY_PMU1(_ah) ((AR_SREV_9462(_ah) || AR_SREV_9565(_ah)) ? 0x16340 : \ + (AR_SREV_9561(_ah) ? 0x16cc0 : 0x16c40)) #define AR_PHY_PMU1_PWD 0x1 #define AR_PHY_PMU1_PWD_S 0 -#define AR_PHY_PMU2 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16344 : 0x16c44) +#define AR_PHY_PMU2(_ah) ((AR_SREV_9462(_ah) || AR_SREV_9565(_ah)) ? 0x16344 : \ + (AR_SREV_9561(_ah) ? 0x16cc4 : 0x16c44)) #define AR_PHY_PMU2_PGM 0x00200000 #define AR_PHY_PMU2_PGM_S 21 @@ -831,8 +851,6 @@ #define AR_PHY_TXGAIN_FORCED_TXBB1DBGAIN 0x0000000e #define AR_PHY_TXGAIN_FORCED_TXBB1DBGAIN_S 1 -#define AR_PHY_POWER_TX_RATE1 0x9934 -#define AR_PHY_POWER_TX_RATE2 0x9938 #define AR_PHY_POWER_TX_RATE_MAX 0x993c #define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040 #define PHY_AGC_CLR 0x10000000 @@ -954,7 +972,7 @@ #define AR_PHY_TPC_5_B1 (AR_SM1_BASE + 0x208) #define AR_PHY_TPC_6_B1 (AR_SM1_BASE + 0x20c) #define AR_PHY_TPC_11_B1 (AR_SM1_BASE + 0x220) -#define AR_PHY_PDADC_TAB_1 (AR_SM1_BASE + (AR_SREV_9462_20_OR_LATER(ah) ? \ +#define AR_PHY_PDADC_TAB_1(_ah) (AR_SM1_BASE + (AR_SREV_9462_20_OR_LATER(_ah) ? \ 0x280 : 0x240)) #define AR_PHY_TPC_19_B1 (AR_SM1_BASE + 0x240) #define AR_PHY_TPC_19_B1_ALPHA_THERM 0xff @@ -962,21 +980,6 @@ #define AR_PHY_TX_IQCAL_STATUS_B1 (AR_SM1_BASE + 0x48c) #define AR_PHY_TX_IQCAL_CORR_COEFF_B1(_i) (AR_SM1_BASE + 0x450 + ((_i) << 2)) -/* SM 1 AIC Registers */ - -#define AR_PHY_AIC_CTRL_0_B1 (AR_SM1_BASE + 0x4b0) -#define AR_PHY_AIC_CTRL_1_B1 (AR_SM1_BASE + 0x4b4) -#define AR_PHY_AIC_CTRL_2_B1 (AR_SM1_BASE + 0x4b8) -#define AR_PHY_AIC_STAT_0_B1 (AR_SM1_BASE + (AR_SREV_9462_10(ah) ? \ - 0x4c0 : 0x4c4)) -#define AR_PHY_AIC_STAT_1_B1 (AR_SM1_BASE + (AR_SREV_9462_10(ah) ? \ - 0x4c4 : 0x4c8)) -#define AR_PHY_AIC_CTRL_4_B1 (AR_SM1_BASE + 0x4c0) -#define AR_PHY_AIC_STAT_2_B1 (AR_SM1_BASE + 0x4cc) - -#define AR_PHY_AIC_SRAM_ADDR_B1 (AR_SM1_BASE + 0x5f0) -#define AR_PHY_AIC_SRAM_DATA_B1 (AR_SM1_BASE + 0x5f4) - #define AR_PHY_RTT_TABLE_SW_INTF_B(i) (0x384 + ((i) ? \ AR_SM1_BASE : AR_SM_BASE)) #define AR_PHY_RTT_TABLE_SW_INTF_1_B(i) (0x388 + ((i) ? \ @@ -1036,13 +1039,6 @@ #define AR_PHY_TX_IQCAL_STATUS_B2_FAILED 0x00000001 -/* - * AGC 3 Register Map - */ -#define AR_AGC3_BASE 0xce00 - -#define AR_PHY_RSSI_3 (AR_AGC3_BASE + 0x180) - /* GLB Registers */ #define AR_GLB_BASE 0x20000 #define AR_GLB_GPIO_CONTROL (AR_GLB_BASE) @@ -1147,7 +1143,7 @@ #define AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT 0x0ffe0000 #define AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT_S 17 -#define AR_PHY_PAPRD_TRAINER_CNTL1 (AR_SM_BASE + (AR_SREV_9485(ah) ? 0x580 : 0x490)) +#define AR_PHY_PAPRD_TRAINER_CNTL1(_ah) (AR_SM_BASE + (AR_SREV_9485(_ah) ? 0x580 : 0x490)) #define AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE 0x00000001 #define AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE_S 0 @@ -1164,12 +1160,12 @@ #define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP 0x0003f000 #define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP_S 12 -#define AR_PHY_PAPRD_TRAINER_CNTL2 (AR_SM_BASE + (AR_SREV_9485(ah) ? 0x584 : 0x494)) +#define AR_PHY_PAPRD_TRAINER_CNTL2(_ah) (AR_SM_BASE + (AR_SREV_9485(_ah) ? 0x584 : 0x494)) #define AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN 0xFFFFFFFF #define AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN_S 0 -#define AR_PHY_PAPRD_TRAINER_CNTL3 (AR_SM_BASE + (AR_SREV_9485(ah) ? 0x588 : 0x498)) +#define AR_PHY_PAPRD_TRAINER_CNTL3(_ah) (AR_SM_BASE + (AR_SREV_9485(_ah) ? 0x588 : 0x498)) #define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE 0x0000003f #define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE_S 0 @@ -1186,7 +1182,7 @@ #define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE 0x20000000 #define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE_S 29 -#define AR_PHY_PAPRD_TRAINER_CNTL4 (AR_SM_BASE + (AR_SREV_9485(ah) ? 0x58c : 0x49c)) +#define AR_PHY_PAPRD_TRAINER_CNTL4(_ah) (AR_SM_BASE + (AR_SREV_9485(_ah) ? 0x58c : 0x49c)) #define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES 0x03ff0000 #define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES_S 16 @@ -1206,7 +1202,7 @@ #define AR_PHY_PAPRD_PRE_POST_SCALING 0x3FFFF #define AR_PHY_PAPRD_PRE_POST_SCALING_S 0 -#define AR_PHY_PAPRD_TRAINER_STAT1 (AR_SM_BASE + (AR_SREV_9485(ah) ? 0x590 : 0x4a0)) +#define AR_PHY_PAPRD_TRAINER_STAT1(_ah) (AR_SM_BASE + (AR_SREV_9485(_ah) ? 0x590 : 0x4a0)) #define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE 0x00000001 #define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE_S 0 @@ -1221,7 +1217,7 @@ #define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR 0x0001fe00 #define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR_S 9 -#define AR_PHY_PAPRD_TRAINER_STAT2 (AR_SM_BASE + (AR_SREV_9485(ah) ? 0x594 : 0x4a4)) +#define AR_PHY_PAPRD_TRAINER_STAT2(_ah) (AR_SM_BASE + (AR_SREV_9485(_ah) ? 0x594 : 0x4a4)) #define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_VAL 0x0000ffff #define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_VAL_S 0 @@ -1230,7 +1226,7 @@ #define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_IDX 0x00600000 #define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_IDX_S 21 -#define AR_PHY_PAPRD_TRAINER_STAT3 (AR_SM_BASE + (AR_SREV_9485(ah) ? 0x598 : 0x4a8)) +#define AR_PHY_PAPRD_TRAINER_STAT3(_ah) (AR_SM_BASE + (AR_SREV_9485(_ah) ? 0x598 : 0x4a8)) #define AR_PHY_PAPRD_TRAINER_STAT3_PAPRD_TRAIN_SAMPLES_CNT 0x000fffff #define AR_PHY_PAPRD_TRAINER_STAT3_PAPRD_TRAIN_SAMPLES_CNT_S 0 @@ -1319,4 +1315,6 @@ #define AR_PHY_65NM_RXRF_AGC_AGC_OUT 0x00000004 #define AR_PHY_65NM_RXRF_AGC_AGC_OUT_S 2 +#define AR9300_DFS_FIRPWR -28 + #endif /* AR9003_PHY_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c index 74de3539c2c8..e4d11fa7fe8c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c @@ -106,7 +106,7 @@ void ar9003_hw_rtt_load_hist(struct ath_hw *ah) int chain, i; for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { - if (!(ah->rxchainmask & (1 << chain))) + if (!(ah->caps.rx_chainmask & (1 << chain))) continue; for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) { ar9003_hw_rtt_load_hist_entry(ah, chain, i, @@ -118,6 +118,27 @@ void ar9003_hw_rtt_load_hist(struct ath_hw *ah) } } +static void ar9003_hw_patch_rtt(struct ath_hw *ah, int index, int chain) +{ + int agc, caldac; + + if (!test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags)) + return; + + if ((index != 5) || (chain >= 2)) + return; + + agc = REG_READ_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain), + AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE); + if (!agc) + return; + + caldac = ah->caldata->caldac[chain]; + ah->caldata->rtt_table[chain][index] &= 0xFFFF05FF; + caldac = (caldac & 0x20) | ((caldac & 0x1F) << 7); + ah->caldata->rtt_table[chain][index] |= (caldac << 4); +} + static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index) { u32 val; @@ -150,18 +171,21 @@ void ar9003_hw_rtt_fill_hist(struct ath_hw *ah) int chain, i; for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { - if (!(ah->rxchainmask & (1 << chain))) + if (!(ah->caps.rx_chainmask & (1 << chain))) continue; for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) { ah->caldata->rtt_table[chain][i] = ar9003_hw_rtt_fill_hist_entry(ah, chain, i); + + ar9003_hw_patch_rtt(ah, i, chain); + ath_dbg(ath9k_hw_common(ah), CALIBRATE, "RTT value at idx %d, chain %d is: 0x%x\n", i, chain, ah->caldata->rtt_table[chain][i]); } } - ah->caldata->rtt_done = true; + set_bit(RTT_DONE, &ah->caldata->cal_flags); } void ar9003_hw_rtt_clear_hist(struct ath_hw *ah) @@ -169,14 +193,14 @@ void ar9003_hw_rtt_clear_hist(struct ath_hw *ah) int chain, i; for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { - if (!(ah->rxchainmask & (1 << chain))) + if (!(ah->caps.rx_chainmask & (1 << chain))) continue; for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) ar9003_hw_rtt_load_hist_entry(ah, chain, i, 0); } if (ah->caldata) - ah->caldata->rtt_done = false; + clear_bit(RTT_DONE, &ah->caldata->cal_flags); } bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan) @@ -186,11 +210,37 @@ bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan) if (!ah->caldata) return false; - if (!ah->caldata->rtt_done) + if (test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags)) { + if (IS_CHAN_2GHZ(chan)){ + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0), + AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, + ah->caldata->caldac[0]); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1), + AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, + ah->caldata->caldac[1]); + } else { + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0), + AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, + ah->caldata->caldac[0]); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1), + AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, + ah->caldata->caldac[1]); + } + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1), + AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1); + REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0), + AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1); + } + + if (!test_bit(RTT_DONE, &ah->caldata->cal_flags)) return false; ar9003_hw_rtt_enable(ah); - ar9003_hw_rtt_set_mask(ah, 0x10); + + if (test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags)) + ar9003_hw_rtt_set_mask(ah, 0x30); + else + ar9003_hw_rtt_set_mask(ah, 0x10); if (!ath9k_hw_rfbus_req(ah)) { ath_err(ath9k_hw_common(ah), "Could not stop baseband\n"); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.h b/drivers/net/wireless/ath/ath9k/ar9003_rtt.h index a43b30d723a4..6290467a75a0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_rtt.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.h @@ -17,6 +17,7 @@ #ifndef AR9003_RTT_H #define AR9003_RTT_H +#ifdef CONFIG_ATH9K_PCOEM void ar9003_hw_rtt_enable(struct ath_hw *ah); void ar9003_hw_rtt_disable(struct ath_hw *ah); void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask); @@ -25,5 +26,40 @@ void ar9003_hw_rtt_load_hist(struct ath_hw *ah); void ar9003_hw_rtt_fill_hist(struct ath_hw *ah); void ar9003_hw_rtt_clear_hist(struct ath_hw *ah); bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan); +#else +static inline void ar9003_hw_rtt_enable(struct ath_hw *ah) +{ +} + +static inline void ar9003_hw_rtt_disable(struct ath_hw *ah) +{ +} + +static inline void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask) +{ +} + +static inline bool ar9003_hw_rtt_force_restore(struct ath_hw *ah) +{ + return false; +} + +static inline void ar9003_hw_rtt_load_hist(struct ath_hw *ah) +{ +} + +static inline void ar9003_hw_rtt_fill_hist(struct ath_hw *ah) +{ +} + +static inline void ar9003_hw_rtt_clear_hist(struct ath_hw *ah) +{ +} + +static inline bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan) +{ + return false; +} +#endif #endif diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c new file mode 100644 index 000000000000..ac32afbf2c97 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/export.h> +#include "ath9k.h" +#include "reg.h" +#include "reg_wow.h" +#include "hw-ops.h" + +static void ath9k_hw_set_sta_powersave(struct ath_hw *ah) +{ + if (!ath9k_hw_mci_is_enabled(ah)) + goto set; + /* + * If MCI is being used, set PWR_SAV only when MCI's + * PS state is disabled. + */ + if (ar9003_mci_state(ah, MCI_STATE_GET_WLAN_PS_STATE) != MCI_PS_DISABLE) + return; +set: + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); +} + +static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + ath9k_hw_set_sta_powersave(ah); + + /* set rx disable bit */ + REG_WRITE(ah, AR_CR, AR_CR_RXD); + + if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE(ah), 0, AH_WAIT_TIMEOUT)) { + ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", + REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); + return; + } + + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { + if (!REG_READ(ah, AR_MAC_PCU_GEN_TIMER_TSF_SEL)) + REG_CLR_BIT(ah, AR_DIRECT_CONNECT, AR_DC_TSF2_ENABLE); + } else if (AR_SREV_9485(ah)){ + if (!(REG_READ(ah, AR_NDP2_TIMER_MODE) & + AR_GEN_TIMERS2_MODE_ENABLE_MASK)) + REG_CLR_BIT(ah, AR_DIRECT_CONNECT, AR_DC_TSF2_ENABLE); + } + + if (ath9k_hw_mci_is_enabled(ah)) + REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); + + REG_WRITE(ah, AR_RTC_FORCE_WAKE(ah), AR_RTC_FORCE_WAKE_ON_INT); +} + +static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + u8 sta_mac_addr[ETH_ALEN], ap_mac_addr[ETH_ALEN]; + u32 ctl[13] = {0}; + u32 data_word[KAL_NUM_DATA_WORDS]; + u8 i; + u32 wow_ka_data_word0; + + memcpy(sta_mac_addr, common->macaddr, ETH_ALEN); + memcpy(ap_mac_addr, common->curbssid, ETH_ALEN); + + /* set the transmit buffer */ + ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16)); + ctl[1] = 0; + ctl[4] = 0; + ctl[7] = (ah->txchainmask) << 2; + ctl[2] = 0xf << 16; /* tx_tries 0 */ + + if (IS_CHAN_2GHZ(ah->curchan)) + ctl[3] = 0x1b; /* CCK_1M */ + else + ctl[3] = 0xb; /* OFDM_6M */ + + for (i = 0; i < KAL_NUM_DESC_WORDS; i++) + REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); + + data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) | + (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16); + data_word[1] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | + (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); + data_word[2] = (sta_mac_addr[1] << 24) | (sta_mac_addr[0] << 16) | + (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); + data_word[3] = (sta_mac_addr[5] << 24) | (sta_mac_addr[4] << 16) | + (sta_mac_addr[3] << 8) | (sta_mac_addr[2]); + data_word[4] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | + (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); + data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); + + if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565(ah)) { + /* + * AR9462 2.0 and AR9565 have an extra descriptor word + * (time based discard) compared to other chips. + */ + REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0); + wow_ka_data_word0 = AR_WOW_TXBUF(13); + } else { + wow_ka_data_word0 = AR_WOW_TXBUF(12); + } + + for (i = 0; i < KAL_NUM_DATA_WORDS; i++) + REG_WRITE(ah, (wow_ka_data_word0 + i*4), data_word[i]); +} + +int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, + u8 *user_mask, int pattern_count, + int pattern_len) +{ + int i; + u32 pattern_val, mask_val; + u32 set, clr; + + if (pattern_count >= ah->wow.max_patterns) + return -ENOSPC; + + if (pattern_count < MAX_NUM_PATTERN_LEGACY) + REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count)); + else + REG_SET_BIT(ah, AR_MAC_PCU_WOW4, BIT(pattern_count - 8)); + + for (i = 0; i < MAX_PATTERN_SIZE; i += 4) { + memcpy(&pattern_val, user_pattern, 4); + REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i), + pattern_val); + user_pattern += 4; + } + + for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) { + memcpy(&mask_val, user_mask, 4); + REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val); + user_mask += 4; + } + + if (pattern_count < MAX_NUM_PATTERN_LEGACY) + ah->wow.wow_event_mask |= + BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); + else + ah->wow.wow_event_mask2 |= + BIT((pattern_count - 8) + AR_WOW_PAT_FOUND_SHIFT); + + if (pattern_count < 4) { + set = (pattern_len & AR_WOW_LENGTH_MAX) << + AR_WOW_LEN1_SHIFT(pattern_count); + clr = AR_WOW_LENGTH1_MASK(pattern_count); + REG_RMW(ah, AR_WOW_LENGTH1, set, clr); + } else if (pattern_count < 8) { + set = (pattern_len & AR_WOW_LENGTH_MAX) << + AR_WOW_LEN2_SHIFT(pattern_count); + clr = AR_WOW_LENGTH2_MASK(pattern_count); + REG_RMW(ah, AR_WOW_LENGTH2, set, clr); + } else if (pattern_count < 12) { + set = (pattern_len & AR_WOW_LENGTH_MAX) << + AR_WOW_LEN3_SHIFT(pattern_count); + clr = AR_WOW_LENGTH3_MASK(pattern_count); + REG_RMW(ah, AR_WOW_LENGTH3, set, clr); + } else if (pattern_count < MAX_NUM_PATTERN) { + set = (pattern_len & AR_WOW_LENGTH_MAX) << + AR_WOW_LEN4_SHIFT(pattern_count); + clr = AR_WOW_LENGTH4_MASK(pattern_count); + REG_RMW(ah, AR_WOW_LENGTH4, set, clr); + } + + return 0; +} +EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern); + +u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) +{ + u32 wow_status = 0; + u32 val = 0, rval; + + /* + * Read the WoW status register to know + * the wakeup reason. + */ + rval = REG_READ(ah, AR_WOW_PATTERN); + val = AR_WOW_STATUS(rval); + + /* + * Mask only the WoW events that we have enabled. Sometimes + * we have spurious WoW events from the AR_WOW_PATTERN + * register. This mask will clean it up. + */ + val &= ah->wow.wow_event_mask; + + if (val) { + if (val & AR_WOW_MAGIC_PAT_FOUND) + wow_status |= AH_WOW_MAGIC_PATTERN_EN; + if (AR_WOW_PATTERN_FOUND(val)) + wow_status |= AH_WOW_USER_PATTERN_EN; + if (val & AR_WOW_KEEP_ALIVE_FAIL) + wow_status |= AH_WOW_LINK_CHANGE; + if (val & AR_WOW_BEACON_FAIL) + wow_status |= AH_WOW_BEACON_MISS; + } + + rval = REG_READ(ah, AR_MAC_PCU_WOW4); + val = AR_WOW_STATUS2(rval); + val &= ah->wow.wow_event_mask2; + + if (val) { + if (AR_WOW2_PATTERN_FOUND(val)) + wow_status |= AH_WOW_USER_PATTERN_EN; + } + + /* + * set and clear WOW_PME_CLEAR registers for the chip to + * generate next wow signal. + * disable D3 before accessing other registers ? + */ + + /* do we need to check the bit value 0x01000000 (7-10) ?? */ + REG_RMW(ah, AR_PCIE_PM_CTRL(ah), AR_PMCTRL_WOW_PME_CLR, + AR_PMCTRL_PWR_STATE_D1D3); + + /* + * Clear all events. + */ + REG_WRITE(ah, AR_WOW_PATTERN, + AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN))); + REG_WRITE(ah, AR_MAC_PCU_WOW4, + AR_WOW_CLEAR_EVENTS2(REG_READ(ah, AR_MAC_PCU_WOW4))); + + /* + * restore the beacon threshold to init value + */ + REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); + + /* + * Restore the way the PCI-E reset, Power-On-Reset, external + * PCIE_POR_SHORT pins are tied to its original value. + * Previously just before WoW sleep, we untie the PCI-E + * reset to our Chip's Power On Reset so that any PCI-E + * reset from the bus will not reset our chip + */ + if (ah->is_pciexpress) + ath9k_hw_configpcipowersave(ah, false); + + if (AR_SREV_9462(ah) || AR_SREV_9565(ah) || AR_SREV_9485(ah)) { + u32 dc = REG_READ(ah, AR_DIRECT_CONNECT); + + if (!(dc & AR_DC_TSF2_ENABLE)) + ath9k_hw_gen_timer_start_tsf2(ah); + } + + ah->wow.wow_event_mask = 0; + ah->wow.wow_event_mask2 = 0; + + return wow_status; +} +EXPORT_SYMBOL(ath9k_hw_wow_wakeup); + +static void ath9k_hw_wow_set_arwr_reg(struct ath_hw *ah) +{ + u32 wa_reg; + + if (!ah->is_pciexpress) + return; + + /* + * We need to untie the internal POR (power-on-reset) + * to the external PCI-E reset. We also need to tie + * the PCI-E Phy reset to the PCI-E reset. + */ + wa_reg = REG_READ(ah, AR_WA(ah)); + wa_reg &= ~AR_WA_UNTIE_RESET_EN; + wa_reg |= AR_WA_RESET_EN; + wa_reg |= AR_WA_POR_SHORT; + + REG_WRITE(ah, AR_WA(ah), wa_reg); +} + +void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) +{ + u32 wow_event_mask; + u32 keep_alive, magic_pattern, host_pm_ctrl; + + wow_event_mask = ah->wow.wow_event_mask; + + /* + * AR_PMCTRL_HOST_PME_EN - Override PME enable in configuration + * space and allow MAC to generate WoW anyway. + * + * AR_PMCTRL_PWR_PM_CTRL_ENA - ??? + * + * AR_PMCTRL_AUX_PWR_DET - PCI core SYS_AUX_PWR_DET signal, + * needs to be set for WoW in PCI mode. + * + * AR_PMCTRL_WOW_PME_CLR - WoW Clear Signal going to the MAC. + * + * Set the power states appropriately and enable PME. + * + * Set and clear WOW_PME_CLEAR for the chip + * to generate next wow signal. + */ + REG_SET_BIT(ah, AR_PCIE_PM_CTRL(ah), AR_PMCTRL_HOST_PME_EN | + AR_PMCTRL_PWR_PM_CTRL_ENA | + AR_PMCTRL_AUX_PWR_DET | + AR_PMCTRL_WOW_PME_CLR); + REG_CLR_BIT(ah, AR_PCIE_PM_CTRL(ah), AR_PMCTRL_WOW_PME_CLR); + + /* + * Random Backoff. + * + * 31:28 in AR_WOW_PATTERN : Indicates the number of bits used in the + * contention window. For value N, + * the random backoff will be selected between + * 0 and (2 ^ N) - 1. + */ + REG_SET_BIT(ah, AR_WOW_PATTERN, + AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF)); + + /* + * AIFS time, Slot time, Keep Alive count. + */ + REG_SET_BIT(ah, AR_WOW_COUNT, AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | + AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | + AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT)); + /* + * Beacon timeout. + */ + if (pattern_enable & AH_WOW_BEACON_MISS) + REG_WRITE(ah, AR_WOW_BCN_TIMO, AR_WOW_BEACON_TIMO); + else + REG_WRITE(ah, AR_WOW_BCN_TIMO, AR_WOW_BEACON_TIMO_MAX); + + /* + * Keep alive timeout in ms. + */ + if (!pattern_enable) + REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, AR_WOW_KEEP_ALIVE_NEVER); + else + REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, KAL_TIMEOUT * 32); + + /* + * Keep alive delay in us. + */ + REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, KAL_DELAY * 1000); + + /* + * Create keep alive pattern to respond to beacons. + */ + ath9k_wow_create_keep_alive_pattern(ah); + + /* + * Configure keep alive register. + */ + keep_alive = REG_READ(ah, AR_WOW_KEEP_ALIVE); + + /* Send keep alive timeouts anyway */ + keep_alive &= ~AR_WOW_KEEP_ALIVE_AUTO_DIS; + + if (pattern_enable & AH_WOW_LINK_CHANGE) { + keep_alive &= ~AR_WOW_KEEP_ALIVE_FAIL_DIS; + wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL; + } else { + keep_alive |= AR_WOW_KEEP_ALIVE_FAIL_DIS; + } + + REG_WRITE(ah, AR_WOW_KEEP_ALIVE, keep_alive); + + /* + * We are relying on a bmiss failure, ensure we have + * enough threshold to prevent false positives. + */ + REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, + AR_WOW_BMISSTHRESHOLD); + + if (pattern_enable & AH_WOW_BEACON_MISS) { + wow_event_mask |= AR_WOW_BEACON_FAIL; + REG_SET_BIT(ah, AR_WOW_BCN_EN, AR_WOW_BEACON_FAIL_EN); + } else { + REG_CLR_BIT(ah, AR_WOW_BCN_EN, AR_WOW_BEACON_FAIL_EN); + } + + /* + * Enable the magic packet registers. + */ + magic_pattern = REG_READ(ah, AR_WOW_PATTERN); + magic_pattern |= AR_WOW_MAC_INTR_EN; + + if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) { + magic_pattern |= AR_WOW_MAGIC_EN; + wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND; + } else { + magic_pattern &= ~AR_WOW_MAGIC_EN; + } + + REG_WRITE(ah, AR_WOW_PATTERN, magic_pattern); + + /* + * Enable pattern matching for packets which are less + * than 256 bytes. + */ + REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B, + AR_WOW_PATTERN_SUPPORTED); + + /* + * Set the power states appropriately and enable PME. + */ + host_pm_ctrl = REG_READ(ah, AR_PCIE_PM_CTRL(ah)); + host_pm_ctrl |= AR_PMCTRL_PWR_STATE_D1D3 | + AR_PMCTRL_HOST_PME_EN | + AR_PMCTRL_PWR_PM_CTRL_ENA; + host_pm_ctrl &= ~AR_PCIE_PM_CTRL_ENA; + + if (AR_SREV_9462(ah)) { + /* + * This is needed to prevent the chip waking up + * the host within 3-4 seconds with certain + * platform/BIOS. + */ + host_pm_ctrl &= ~AR_PMCTRL_PWR_STATE_D1D3; + host_pm_ctrl |= AR_PMCTRL_PWR_STATE_D1D3_REAL; + } + + REG_WRITE(ah, AR_PCIE_PM_CTRL(ah), host_pm_ctrl); + + /* + * Enable sequence number generation when asleep. + */ + REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); + + /* To bring down WOW power low margin */ + REG_SET_BIT(ah, AR_PCIE_PHY_REG3, BIT(13)); + + ath9k_hw_wow_set_arwr_reg(ah); + + if (ath9k_hw_mci_is_enabled(ah)) + REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); + + /* HW WoW */ + REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, BIT(5)); + + ath9k_hw_set_powermode_wow_sleep(ah); + ah->wow.wow_event_mask = wow_event_mask; +} +EXPORT_SYMBOL(ath9k_hw_wow_enable); diff --git a/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h index 6e1756bc3833..3e783fc13553 100644 --- a/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h @@ -18,6 +18,10 @@ #ifndef INITVALS_9330_1P1_H #define INITVALS_9330_1P1_H +#define ar9331_1p1_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 + +#define ar9331_modes_high_power_tx_gain_1p1 ar9331_modes_lowest_ob_db_tx_gain_1p1 + static const u32 ar9331_1p1_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, @@ -36,7 +40,7 @@ static const u32 ar9331_1p1_baseband_postamble[][5] = { {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00003221, 0x00003221}, - {0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946222, 0xcf946222}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946220, 0xcf946220}, {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -55,7 +59,7 @@ static const u32 ar9331_1p1_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, {0x0000a2d0, 0x00071982, 0x00071982, 0x00071982, 0x00071982}, {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -252,7 +256,7 @@ static const u32 ar9331_modes_low_ob_db_tx_gain_1p1[][5] = { {0x0000a2e0, 0xffffcc84, 0xffffcc84, 0xffffcc84, 0xffffcc84}, {0x0000a2e4, 0xfffff000, 0xfffff000, 0xfffff000, 0xfffff000}, {0x0000a2e8, 0xfffe0000, 0xfffe0000, 0xfffe0000, 0xfffe0000}, - {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d0, 0x000050d0}, + {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d4, 0x000050d4}, {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, @@ -337,8 +341,6 @@ static const u32 ar9331_modes_low_ob_db_tx_gain_1p1[][5] = { {0x00016284, 0x14d3f000, 0x14d3f000, 0x14d3f000, 0x14d3f000}, }; -#define ar9331_1p1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 - static const u32 ar9331_1p1_xtal_25M[][2] = { /* Addr allmodes */ {0x00007038, 0x000002f8}, @@ -373,17 +375,17 @@ static const u32 ar9331_1p1_radio_core[][2] = { {0x000160b4, 0x92480040}, {0x000160c0, 0x006db6db}, {0x000160c4, 0x0186db60}, - {0x000160c8, 0x6db4db6c}, + {0x000160c8, 0x6db6db6c}, {0x000160cc, 0x6de6c300}, {0x000160d0, 0x14500820}, {0x00016100, 0x04cb0001}, {0x00016104, 0xfff80015}, {0x00016108, 0x00080010}, {0x0001610c, 0x00170000}, - {0x00016140, 0x10800000}, + {0x00016140, 0x50804000}, {0x00016144, 0x01884080}, {0x00016148, 0x000080c0}, - {0x00016280, 0x01000015}, + {0x00016280, 0x01001015}, {0x00016284, 0x14d20000}, {0x00016288, 0x00318000}, {0x0001628c, 0x50000000}, @@ -590,7 +592,7 @@ static const u32 ar9331_1p1_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x0d261800}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, {0x00009fc0, 0x803e4788}, @@ -622,12 +624,12 @@ static const u32 ar9331_1p1_baseband_core[][2] = { {0x0000a370, 0x00000000}, {0x0000a390, 0x00000001}, {0x0000a394, 0x00000444}, - {0x0000a398, 0x001f0e0f}, - {0x0000a39c, 0x0075393f}, - {0x0000a3a0, 0xb79f6427}, - {0x0000a3a4, 0x00000000}, - {0x0000a3a8, 0xaaaaaaaa}, - {0x0000a3ac, 0x3c466478}, + {0x0000a398, 0x00000000}, + {0x0000a39c, 0x210d0401}, + {0x0000a3a0, 0xab9a7144}, + {0x0000a3a4, 0x00000011}, + {0x0000a3a8, 0x3c3c003d}, + {0x0000a3ac, 0x30310030}, {0x0000a3c0, 0x20202020}, {0x0000a3c4, 0x22222220}, {0x0000a3c8, 0x20200020}, @@ -686,100 +688,18 @@ static const u32 ar9331_1p1_baseband_core[][2] = { {0x0000a7dc, 0x00000001}, }; -static const u32 ar9331_modes_high_power_tx_gain_1p1[][5] = { +static const u32 ar9331_1p1_mac_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a}, - {0x0000a2dc, 0xffff2a52, 0xffff2a52, 0xffff2a52, 0xffff2a52}, - {0x0000a2e0, 0xffffcc84, 0xffffcc84, 0xffffcc84, 0xffffcc84}, - {0x0000a2e4, 0xfffff000, 0xfffff000, 0xfffff000, 0xfffff000}, - {0x0000a2e8, 0xfffe0000, 0xfffe0000, 0xfffe0000, 0xfffe0000}, - {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d0, 0x000050d0}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x23000a00, 0x23000a00}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x27000a02, 0x27000a02}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2b000a04, 0x2b000a04}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2d000a20, 0x2d000a20}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x31000a22, 0x31000a22}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000a24, 0x35000a24}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000a43, 0x38000a43}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3b000e42, 0x3b000e42}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x3f000e44, 0x3f000e44}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x42000e64, 0x42000e64}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46000e66, 0x46000e66}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x4a000ea6, 0x4a000ea6}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4a000ea6, 0x4a000ea6}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x4a000ea6, 0x4a000ea6}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x4a000ea6, 0x4a000ea6}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x4a000ea6, 0x4a000ea6}, - {0x0000a580, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a584, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a588, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a58c, 0x11062202, 0x11062202, 0x0b000200, 0x0b000200}, - {0x0000a590, 0x17022e00, 0x17022e00, 0x0f000202, 0x0f000202}, - {0x0000a594, 0x1d000ec2, 0x1d000ec2, 0x11000400, 0x11000400}, - {0x0000a598, 0x25020ec0, 0x25020ec0, 0x15000402, 0x15000402}, - {0x0000a59c, 0x2b020ec3, 0x2b020ec3, 0x19000404, 0x19000404}, - {0x0000a5a0, 0x2f001f04, 0x2f001f04, 0x1b000603, 0x1b000603}, - {0x0000a5a4, 0x35001fc4, 0x35001fc4, 0x1f000a02, 0x1f000a02}, - {0x0000a5a8, 0x3c022f04, 0x3c022f04, 0x23000a04, 0x23000a04}, - {0x0000a5ac, 0x41023e85, 0x41023e85, 0x26000a20, 0x26000a20}, - {0x0000a5b0, 0x48023ec6, 0x48023ec6, 0x2a000e20, 0x2a000e20}, - {0x0000a5b4, 0x4d023f01, 0x4d023f01, 0x2e000e22, 0x2e000e22}, - {0x0000a5b8, 0x53023f4b, 0x53023f4b, 0x31000e24, 0x31000e24}, - {0x0000a5bc, 0x5a027f09, 0x5a027f09, 0x34001640, 0x34001640}, - {0x0000a5c0, 0x5f027fc9, 0x5f027fc9, 0x38001660, 0x38001660}, - {0x0000a5c4, 0x6502feca, 0x6502feca, 0x3b001861, 0x3b001861}, - {0x0000a5c8, 0x6b02ff4a, 0x6b02ff4a, 0x3e001a81, 0x3e001a81}, - {0x0000a5cc, 0x7203feca, 0x7203feca, 0x42001a83, 0x42001a83}, - {0x0000a5d0, 0x7703ff0b, 0x7703ff0b, 0x44001c84, 0x44001c84}, - {0x0000a5d4, 0x7d06ffcb, 0x7d06ffcb, 0x48001ce3, 0x48001ce3}, - {0x0000a5d8, 0x8407ff0b, 0x8407ff0b, 0x4c001ce5, 0x4c001ce5}, - {0x0000a5dc, 0x8907ffcb, 0x8907ffcb, 0x50001ce9, 0x50001ce9}, - {0x0000a5e0, 0x900fff0b, 0x900fff0b, 0x54001ceb, 0x54001ceb}, - {0x0000a5e4, 0x960fffcb, 0x960fffcb, 0x56001eec, 0x56001eec}, - {0x0000a5e8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5ec, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f0, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f4, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5fc, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, - {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, - {0x0000a61c, 0x02008802, 0x02008802, 0x02008802, 0x02008802}, - {0x0000a620, 0x0280c802, 0x0280c802, 0x0280c802, 0x0280c802}, - {0x0000a624, 0x03010a03, 0x03010a03, 0x03010a03, 0x03010a03}, - {0x0000a628, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, - {0x0000a62c, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, - {0x0000a630, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, - {0x0000a634, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, - {0x0000a638, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, - {0x0000a63c, 0x03010c04, 0x03010c04, 0x03010c04, 0x03010c04}, - {0x00016044, 0x034922db, 0x034922db, 0x034922db, 0x034922db}, - {0x00016284, 0x14d3f000, 0x14d3f000, 0x14d3f000, 0x14d3f000}, + {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, + {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, + {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, + {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, + {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, + {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, + {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, + {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, }; -#define ar9331_1p1_mac_postamble ar9300_2p2_mac_postamble - static const u32 ar9331_1p1_soc_preamble[][2] = { /* Addr allmodes */ {0x00007020, 0x00000000}, @@ -1090,11 +1010,4 @@ static const u32 ar9331_common_rx_gain_1p1[][2] = { {0x0000a1fc, 0x00000296}, }; -static const u32 ar9331_common_tx_gain_offset1_1[][1] = { - {0x00000000}, - {0x00000003}, - {0x00000000}, - {0x00000000}, -}; - #endif /* INITVALS_9330_1P1_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h index 57ed8a112173..c4a6ffa55e8c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h @@ -18,6 +18,28 @@ #ifndef INITVALS_9330_1P2_H #define INITVALS_9330_1P2_H +#define ar9331_modes_high_power_tx_gain_1p2 ar9331_modes_high_ob_db_tx_gain_1p2 + +#define ar9331_modes_low_ob_db_tx_gain_1p2 ar9331_modes_high_ob_db_tx_gain_1p2 + +#define ar9331_modes_lowest_ob_db_tx_gain_1p2 ar9331_modes_high_ob_db_tx_gain_1p2 + +#define ar9331_1p2_baseband_core_txfir_coeff_japan_2484 ar9331_1p1_baseband_core_txfir_coeff_japan_2484 + +#define ar9331_1p2_xtal_25M ar9331_1p1_xtal_25M + +#define ar9331_1p2_xtal_40M ar9331_1p1_xtal_40M + +#define ar9331_1p2_soc_postamble ar9331_1p1_soc_postamble + +#define ar9331_1p2_mac_postamble ar9331_1p1_mac_postamble + +#define ar9331_1p2_soc_preamble ar9331_1p1_soc_preamble + +#define ar9331_1p2_mac_core ar9331_1p1_mac_core + +#define ar9331_common_wo_xlna_rx_gain_1p2 ar9331_common_wo_xlna_rx_gain_1p1 + static const u32 ar9331_modes_high_ob_db_tx_gain_1p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d7, 0x000050d7}, @@ -103,57 +125,6 @@ static const u32 ar9331_modes_high_ob_db_tx_gain_1p2[][5] = { {0x0000a63c, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, }; -#define ar9331_modes_high_power_tx_gain_1p2 ar9331_modes_high_ob_db_tx_gain_1p2 - -#define ar9331_modes_low_ob_db_tx_gain_1p2 ar9331_modes_high_power_tx_gain_1p2 - -#define ar9331_modes_lowest_ob_db_tx_gain_1p2 ar9331_modes_low_ob_db_tx_gain_1p2 - -static const u32 ar9331_1p2_baseband_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, - {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, - {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, - {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, - {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, - {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, - {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a4, 0x037216a4}, - {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, - {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, - {0x00009e10, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e}, - {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, - {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, - {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, - {0x00009e2c, 0x0000001c, 0x0000001c, 0x00003221, 0x00003221}, - {0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946222, 0xcf946222}, - {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, - {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, - {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, - {0x0000a204, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0}, - {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, - {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, - {0x0000a234, 0x00000fff, 0x00000fff, 0x10000fff, 0x00000fff}, - {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, - {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, - {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, - {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, - {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, - {0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501}, - {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, - {0x0000a284, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071981}, - {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, - {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000ae04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, - {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -}; - static const u32 ar9331_1p2_radio_core[][2] = { /* Addr allmodes */ {0x00016000, 0x36db6db6}, @@ -219,24 +190,318 @@ static const u32 ar9331_1p2_radio_core[][2] = { {0x000163d4, 0x00000000}, }; -#define ar9331_1p2_baseband_core_txfir_coeff_japan_2484 ar9331_1p1_baseband_core_txfir_coeff_japan_2484 - -#define ar9331_1p2_xtal_25M ar9331_1p1_xtal_25M - -#define ar9331_1p2_xtal_40M ar9331_1p1_xtal_40M - -#define ar9331_1p2_baseband_core ar9331_1p1_baseband_core - -#define ar9331_1p2_soc_postamble ar9331_1p1_soc_postamble - -#define ar9331_1p2_mac_postamble ar9331_1p1_mac_postamble - -#define ar9331_1p2_soc_preamble ar9331_1p1_soc_preamble - -#define ar9331_1p2_mac_core ar9331_1p1_mac_core +static const u32 ar9331_1p2_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a8f6b}, + {0x0000980c, 0x04800000}, + {0x00009814, 0x9280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x5f3ca3de}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14750600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x32840bbe}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0x00000000}, + {0x00009c08, 0x03200000}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x1883800a}, + {0x00009d10, 0x01834061}, + {0x00009d14, 0x00c00400}, + {0x00009d18, 0x00000000}, + {0x00009e08, 0x0038233c}, + {0x00009e24, 0x9927b515}, + {0x00009e28, 0x12ef0200}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e40, 0x0d261800}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009fc0, 0x803e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x0000a20c, 0x00000000}, + {0x0000a220, 0x00000000}, + {0x0000a224, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a2a0, 0x00000001}, + {0x0000a2c0, 0x00000001}, + {0x0000a2c8, 0x00000000}, + {0x0000a2cc, 0x18c43433}, + {0x0000a2d4, 0x00000000}, + {0x0000a2dc, 0x00000000}, + {0x0000a2e0, 0x00000000}, + {0x0000a2e4, 0x00000000}, + {0x0000a2e8, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a364, 0x00000000}, + {0x0000a370, 0x00000000}, + {0x0000a390, 0x00000001}, + {0x0000a394, 0x00000444}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, + {0x0000a3a4, 0x00000000}, + {0x0000a3a8, 0xaaaaaaaa}, + {0x0000a3ac, 0x3c466478}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000006}, + {0x0000a3f8, 0x0cdbd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce739ce}, + {0x0000a418, 0x2d001dce}, + {0x0000a41c, 0x1ce739ce}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce739ce}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00000000}, + {0x0000a440, 0x00000000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x04000000}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a458, 0x00000000}, + {0x0000a640, 0x00000000}, + {0x0000a644, 0x3fad9d74}, + {0x0000a648, 0x0048060a}, + {0x0000a64c, 0x00003c37}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x09080504}, + {0x0000a678, 0x0d0c0b0a}, + {0x0000a67c, 0x13121110}, + {0x0000a680, 0x31301514}, + {0x0000a684, 0x35343332}, + {0x0000a688, 0x00000036}, + {0x0000a690, 0x00000838}, + {0x0000a7c0, 0x00000000}, + {0x0000a7c4, 0xfffffffc}, + {0x0000a7c8, 0x00000000}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000001}, +}; -#define ar9331_common_wo_xlna_rx_gain_1p2 ar9331_common_wo_xlna_rx_gain_1p1 +static const u32 ar9331_1p2_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, + {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, + {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, + {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a4, 0x037216a4}, + {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009e10, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e}, + {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00003221, 0x00003221}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946220, 0xcf946220}, + {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x0000a234, 0x00000fff, 0x00000fff, 0x10000fff, 0x00000fff}, + {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, + {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071981}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +}; -#define ar9331_common_rx_gain_1p2 ar9485_common_rx_gain_1_1 +static const u32 ar9331_common_rx_gain_1p2[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x01800082}, + {0x0000a014, 0x01820181}, + {0x0000a018, 0x01840183}, + {0x0000a01c, 0x01880185}, + {0x0000a020, 0x018a0189}, + {0x0000a024, 0x02850284}, + {0x0000a028, 0x02890288}, + {0x0000a02c, 0x03850384}, + {0x0000a030, 0x03890388}, + {0x0000a034, 0x038b038a}, + {0x0000a038, 0x038d038c}, + {0x0000a03c, 0x03910390}, + {0x0000a040, 0x03930392}, + {0x0000a044, 0x03950394}, + {0x0000a048, 0x00000396}, + {0x0000a04c, 0x00000000}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x28282828}, + {0x0000a084, 0x28282828}, + {0x0000a088, 0x28282828}, + {0x0000a08c, 0x28282828}, + {0x0000a090, 0x28282828}, + {0x0000a094, 0x21212128}, + {0x0000a098, 0x171c1c1c}, + {0x0000a09c, 0x02020212}, + {0x0000a0a0, 0x00000202}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x111f1100}, + {0x0000a0c8, 0x111d111e}, + {0x0000a0cc, 0x111b111c}, + {0x0000a0d0, 0x22032204}, + {0x0000a0d4, 0x22012202}, + {0x0000a0d8, 0x221f2200}, + {0x0000a0dc, 0x221d221e}, + {0x0000a0e0, 0x33013302}, + {0x0000a0e4, 0x331f3300}, + {0x0000a0e8, 0x4402331e}, + {0x0000a0ec, 0x44004401}, + {0x0000a0f0, 0x441e441f}, + {0x0000a0f4, 0x55015502}, + {0x0000a0f8, 0x551f5500}, + {0x0000a0fc, 0x6602551e}, + {0x0000a100, 0x66006601}, + {0x0000a104, 0x661e661f}, + {0x0000a108, 0x7703661d}, + {0x0000a10c, 0x77017702}, + {0x0000a110, 0x00007700}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x111f1100}, + {0x0000a148, 0x111d111e}, + {0x0000a14c, 0x111b111c}, + {0x0000a150, 0x22032204}, + {0x0000a154, 0x22012202}, + {0x0000a158, 0x221f2200}, + {0x0000a15c, 0x221d221e}, + {0x0000a160, 0x33013302}, + {0x0000a164, 0x331f3300}, + {0x0000a168, 0x4402331e}, + {0x0000a16c, 0x44004401}, + {0x0000a170, 0x441e441f}, + {0x0000a174, 0x55015502}, + {0x0000a178, 0x551f5500}, + {0x0000a17c, 0x6602551e}, + {0x0000a180, 0x66006601}, + {0x0000a184, 0x661e661f}, + {0x0000a188, 0x7703661d}, + {0x0000a18c, 0x77017702}, + {0x0000a190, 0x00007700}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000296}, +}; #endif /* INITVALS_9330_1P2_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h index 25db9215985a..3da4ea564148 100644 --- a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -18,6 +18,20 @@ #ifndef INITVALS_9340_H #define INITVALS_9340_H +#define ar9340_1p0_mac_postamble ar9300_2p2_mac_postamble + +#define ar9340_1p0_soc_postamble ar9300_2p2_soc_postamble + +#define ar9340Modes_fast_clock_1p0 ar9300Modes_fast_clock_2p2 + +#define ar9340Common_rx_gain_table_1p0 ar9300Common_rx_gain_table_2p2 + +#define ar9340Common_wo_xlna_rx_gain_table_1p0 ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define ar9340_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 + +#define ar9340_1p0_baseband_postamble_dfs_channel ar9300_2p2_baseband_postamble_dfs_channel + static const u32 ar9340_1p0_radio_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800}, @@ -100,8 +114,6 @@ static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = { {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, }; -#define ar9340Modes_fast_clock_1p0 ar9300Modes_fast_clock_2p2 - static const u32 ar9340_1p0_radio_core[][2] = { /* Addr allmodes */ {0x00016000, 0x36db6db6}, @@ -215,16 +227,12 @@ static const u32 ar9340_1p0_radio_core_40M[][2] = { {0x0000824c, 0x0001e800}, }; -#define ar9340_1p0_mac_postamble ar9300_2p2_mac_postamble - -#define ar9340_1p0_soc_postamble ar9300_2p2_soc_postamble - static const u32 ar9340_1p0_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, {0x00009820, 0x206a022e, 0x206a022e, 0x206a022e, 0x206a022e}, {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x00009828, 0x06903081, 0x06903081, 0x09103881, 0x09103881}, {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, @@ -237,7 +245,7 @@ static const u32 ar9340_1p0_baseband_postamble[][5] = { {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946220, 0xcf946220}, {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -257,7 +265,7 @@ static const u32 ar9340_1p0_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, {0x0000a288, 0x00000220, 0x00000220, 0x00000110, 0x00000110}, {0x0000a28c, 0x00011111, 0x00011111, 0x00022222, 0x00022222}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, {0x0000a2d0, 0x00041983, 0x00041983, 0x00041982, 0x00041982}, {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -310,7 +318,7 @@ static const u32 ar9340_1p0_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x0d261800}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, {0x00009e54, 0x00000000}, @@ -613,367 +621,6 @@ static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][5] = { {0x00016448, 0x8e481666, 0x8e481666, 0x8e481266, 0x8e481266}, }; -static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, - {0x00009820, 0x206a022e, 0x206a022e, 0x206a00ae, 0x206a00ae}, - {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, - {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec82d2e, 0x7ec82d2e}, - {0x0000a2dc, 0xfef5d402, 0xfef5d402, 0xfdab5b52, 0xfdab5b52}, - {0x0000a2e0, 0xfe896600, 0xfe896600, 0xfd339c84, 0xfd339c84}, - {0x0000a2e4, 0xff01f800, 0xff01f800, 0xfec3e000, 0xfec3e000}, - {0x0000a2e8, 0xfffe0000, 0xfffe0000, 0xfffc0000, 0xfffc0000}, - {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, - {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, - {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, - {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, - {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, - {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, - {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, - {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, - {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, - {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, - {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, - {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, - {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, - {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, - {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, - {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, - {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, - {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, - {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, - {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, - {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, - {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, - {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, - {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, - {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, - {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, - {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, - {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, - {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, - {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, - {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, - {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, - {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, - {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, - {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, - {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, - {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, - {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, - {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, - {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, - {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, - {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, - {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, - {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, - {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, - {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, - {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, - {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, - {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x00016044, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, - {0x00016048, 0x8e480086, 0x8e480086, 0x8e480086, 0x8e480086}, - {0x00016444, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, - {0x00016448, 0x8e480086, 0x8e480086, 0x8e480086, 0x8e480086}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, - {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, - {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, - {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, - {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000b2dc, 0xfef5d402, 0xfef5d402, 0xfdab5b52, 0xfdab5b52}, - {0x0000b2e0, 0xfe896600, 0xfe896600, 0xfd339c84, 0xfd339c84}, - {0x0000b2e4, 0xff01f800, 0xff01f800, 0xfec3e000, 0xfec3e000}, - {0x0000b2e8, 0xfffe0000, 0xfffe0000, 0xfffc0000, 0xfffc0000}, -}; - -static const u32 ar9340Common_rx_gain_table_1p0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x01910190}, - {0x0000a030, 0x01930192}, - {0x0000a034, 0x01950194}, - {0x0000a038, 0x038a0196}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x22222229}, - {0x0000a084, 0x1d1d1d1d}, - {0x0000a088, 0x1d1d1d1d}, - {0x0000a08c, 0x1d1d1d1d}, - {0x0000a090, 0x171d1d1d}, - {0x0000a094, 0x11111717}, - {0x0000a098, 0x00030311}, - {0x0000a09c, 0x00000000}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x23232323}, - {0x0000b084, 0x21232323}, - {0x0000b088, 0x19191c1e}, - {0x0000b08c, 0x12141417}, - {0x0000b090, 0x07070e0e}, - {0x0000b094, 0x03030305}, - {0x0000b098, 0x00000003}, - {0x0000b09c, 0x00000000}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, @@ -1437,8 +1084,6 @@ static const u32 ar9340_1p0_mac_core[][2] = { {0x000083d0, 0x000101ff}, }; -#define ar9340Common_wo_xlna_rx_gain_table_1p0 ar9300Common_wo_xlna_rx_gain_table_2p2 - static const u32 ar9340_1p0_soc_preamble[][2] = { /* Addr allmodes */ {0x00007008, 0x00000000}, @@ -1447,4 +1092,106 @@ static const u32 ar9340_1p0_soc_preamble[][2] = { {0x00007038, 0x000004c2}, }; +static const u32 ar9340_cus227_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400}, + {0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402}, + {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2c022220, 0x2c022220, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x30022222, 0x30022222, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x35022225, 0x35022225, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x3b02222a, 0x3b02222a, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x3f02222c, 0x3f02222c, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x61024a6c, 0x61024a6c, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x66026a6c, 0x66026a6c, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x7002708c, 0x7002708c, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x7302b08a, 0x7302b08a, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400}, + {0x0000a598, 0x21820220, 0x21820220, 0x15800402, 0x15800402}, + {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, + {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, + {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, + {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, + {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016048, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266}, + {0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015}, + {0x00016288, 0x30318000, 0x30318000, 0x00318000, 0x00318000}, + {0x00016444, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016448, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266}, + {0x0000a3a4, 0x00000011, 0x00000011, 0x00000011, 0x00000011}, + {0x0000a3a8, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c, 0x3c3c3c3c}, + {0x0000a3ac, 0x30303030, 0x30303030, 0x30303030, 0x30303030}, +}; + #endif /* INITVALS_9340_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h index 092b9d412e7f..b00dd649453d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -20,7 +20,15 @@ /* AR9462 2.0 */ -static const u32 ar9462_modes_fast_clock_2p0[][3] = { +#define ar9462_2p0_mac_postamble ar9331_1p1_mac_postamble + +#define ar9462_2p0_common_wo_xlna_rx_gain ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define ar9462_2p0_common_5g_xlna_only_rxgain ar9462_2p0_common_mixed_rx_gain + +#define ar9462_2p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 + +static const u32 ar9462_2p0_modes_fast_clock[][3] = { /* Addr 5G_HT20 5G_HT40 */ {0x00001030, 0x00000268, 0x000004d0}, {0x00001070, 0x0000018c, 0x00000318}, @@ -33,13 +41,6 @@ static const u32 ar9462_modes_fast_clock_2p0[][3] = { {0x0000a254, 0x00000898, 0x00001130}, }; -static const u32 ar9462_pciephy_clkreq_enable_L1_2p0[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x18253ede}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0003780c}, -}; - static const u32 ar9462_2p0_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d}, @@ -56,9 +57,9 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e}, {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, - {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c780, 0xcfd5c280}, {0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -78,7 +79,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -95,11 +96,11 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000}, {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, - {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000ae20, 0x000001a6, 0x000001a6, 0x000001aa, 0x000001aa}, {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, }; -static const u32 ar9462_common_rx_gain_table_2p0[][2] = { +static const u32 ar9462_2p0_common_rx_gain[][2] = { /* Addr allmodes */ {0x0000a000, 0x00010000}, {0x0000a004, 0x00030002}, @@ -359,20 +360,13 @@ static const u32 ar9462_common_rx_gain_table_2p0[][2] = { {0x0000b1fc, 0x00000196}, }; -static const u32 ar9462_pciephy_clkreq_disable_L1_2p0[][2] = { +static const u32 ar9462_2p0_pciephy_clkreq_disable_L1[][2] = { /* Addr allmodes */ {0x00018c00, 0x18213ede}, {0x00018c04, 0x000801d8}, {0x00018c08, 0x0003780c}, }; -static const u32 ar9462_pciephy_pll_on_clkreq_disable_L1_2p0[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x18212ede}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0003780c}, -}; - static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808}, @@ -380,274 +374,7 @@ static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = { {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, }; -static const u32 ar9462_common_wo_xlna_rx_gain_table_2p0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x32323232}, - {0x0000b084, 0x2f2f3232}, - {0x0000b088, 0x23282a2d}, - {0x0000b08c, 0x1c1e2123}, - {0x0000b090, 0x14171919}, - {0x0000b094, 0x0e0e1214}, - {0x0000b098, 0x03050707}, - {0x0000b09c, 0x00030303}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p0_baseband_core_txfir_coeff_japan_2484[][2] = { - /* Addr allmodes */ - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x6f7f0301}, - {0x0000a3a0, 0xca9228ee}, -}; - -static const u32 ar9462_modes_low_ob_db_tx_gain_table_2p0[][5] = { +static const u32 ar9462_2p0_modes_low_ob_db_tx_gain[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, @@ -879,7 +606,7 @@ static const u32 ar9462_2p0_radio_postamble[][5] = { {0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000}, }; -static const u32 ar9462_modes_mix_ob_db_tx_gain_table_2p0[][5] = { +static const u32 ar9462_2p0_modes_mix_ob_db_tx_gain[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, @@ -942,7 +669,7 @@ static const u32 ar9462_modes_mix_ob_db_tx_gain_table_2p0[][5] = { {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, }; -static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = { +static const u32 ar9462_2p0_modes_high_ob_db_tx_gain[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, @@ -1240,19 +967,7 @@ static const u32 ar9462_2p0_mac_core[][2] = { {0x000083d0, 0x000301ff}, }; -static const u32 ar9462_2p0_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; - -static const u32 ar9462_common_mixed_rx_gain_table_2p0[][2] = { +static const u32 ar9462_2p0_common_mixed_rx_gain[][2] = { /* Addr allmodes */ {0x0000a000, 0x00010000}, {0x0000a004, 0x00030002}, @@ -1517,266 +1232,6 @@ static const u32 ar9462_2p0_baseband_postamble_5g_xlna[][5] = { {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, }; -static const u32 ar9462_2p0_5g_xlna_only_rxgain[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x2a2d2f32}, - {0x0000b084, 0x21232328}, - {0x0000b088, 0x19191c1e}, - {0x0000b08c, 0x12141417}, - {0x0000b090, 0x07070e0e}, - {0x0000b094, 0x03030305}, - {0x0000b098, 0x00000003}, - {0x0000b09c, 0x00000000}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - static const u32 ar9462_2p0_baseband_core_mix_rxgain[][2] = { /* Addr allmodes */ {0x00009fd0, 0x0a2d6b93}, diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h index 4dbc294df7e3..0f8745ec73b1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h @@ -20,6 +20,44 @@ /* AR9462 2.1 */ +#define ar9462_2p1_mac_postamble ar9462_2p0_mac_postamble + +#define ar9462_2p1_baseband_core ar9462_2p0_baseband_core + +#define ar9462_2p1_radio_core ar9462_2p0_radio_core + +#define ar9462_2p1_radio_postamble ar9462_2p0_radio_postamble + +#define ar9462_2p1_soc_postamble ar9462_2p0_soc_postamble + +#define ar9462_2p1_radio_postamble_sys2ant ar9462_2p0_radio_postamble_sys2ant + +#define ar9462_2p1_common_rx_gain ar9462_2p0_common_rx_gain + +#define ar9462_2p1_common_mixed_rx_gain ar9462_2p0_common_mixed_rx_gain + +#define ar9462_2p1_common_5g_xlna_only_rxgain ar9462_2p0_common_5g_xlna_only_rxgain + +#define ar9462_2p1_baseband_core_mix_rxgain ar9462_2p0_baseband_core_mix_rxgain + +#define ar9462_2p1_baseband_postamble_mix_rxgain ar9462_2p0_baseband_postamble_mix_rxgain + +#define ar9462_2p1_baseband_postamble_5g_xlna ar9462_2p0_baseband_postamble_5g_xlna + +#define ar9462_2p1_common_wo_xlna_rx_gain ar9462_2p0_common_wo_xlna_rx_gain + +#define ar9462_2p1_modes_low_ob_db_tx_gain ar9462_2p0_modes_low_ob_db_tx_gain + +#define ar9462_2p1_modes_high_ob_db_tx_gain ar9462_2p0_modes_high_ob_db_tx_gain + +#define ar9462_2p1_modes_mix_ob_db_tx_gain ar9462_2p0_modes_mix_ob_db_tx_gain + +#define ar9462_2p1_modes_fast_clock ar9462_2p0_modes_fast_clock + +#define ar9462_2p1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 + +#define ar9462_2p1_pciephy_clkreq_disable_L1 ar9462_2p0_pciephy_clkreq_disable_L1 + static const u32 ar9462_2p1_mac_core[][2] = { /* Addr allmodes */ {0x00000008, 0x00000000}, @@ -183,168 +221,6 @@ static const u32 ar9462_2p1_mac_core[][2] = { {0x000083d0, 0x000301ff}, }; -static const u32 ar9462_2p1_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; - -static const u32 ar9462_2p1_baseband_core[][2] = { - /* Addr allmodes */ - {0x00009800, 0xafe68e30}, - {0x00009804, 0xfd14e000}, - {0x00009808, 0x9c0a9f6b}, - {0x0000980c, 0x04900000}, - {0x00009814, 0x9280c00a}, - {0x00009818, 0x00000000}, - {0x0000981c, 0x00020028}, - {0x00009834, 0x6400a290}, - {0x00009838, 0x0108ecff}, - {0x0000983c, 0x0d000600}, - {0x00009880, 0x201fff00}, - {0x00009884, 0x00001042}, - {0x000098a4, 0x00200400}, - {0x000098b0, 0x32440bbe}, - {0x000098d0, 0x004b6a8e}, - {0x000098d4, 0x00000820}, - {0x000098dc, 0x00000000}, - {0x000098e4, 0x01ffffff}, - {0x000098e8, 0x01ffffff}, - {0x000098ec, 0x01ffffff}, - {0x000098f0, 0x00000000}, - {0x000098f4, 0x00000000}, - {0x00009bf0, 0x80000000}, - {0x00009c04, 0xff55ff55}, - {0x00009c08, 0x0320ff55}, - {0x00009c0c, 0x00000000}, - {0x00009c10, 0x00000000}, - {0x00009c14, 0x00046384}, - {0x00009c18, 0x05b6b440}, - {0x00009c1c, 0x00b6b440}, - {0x00009d00, 0xc080a333}, - {0x00009d04, 0x40206c10}, - {0x00009d08, 0x009c4060}, - {0x00009d0c, 0x9883800a}, - {0x00009d10, 0x01834061}, - {0x00009d14, 0x00c0040b}, - {0x00009d18, 0x00000000}, - {0x00009e08, 0x0038230c}, - {0x00009e24, 0x990bb515}, - {0x00009e28, 0x0c6f0000}, - {0x00009e30, 0x06336f77}, - {0x00009e34, 0x6af6532f}, - {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x15262820}, - {0x00009e4c, 0x00001004}, - {0x00009e50, 0x00ff03f1}, - {0x00009e54, 0xe4c555c2}, - {0x00009e58, 0xfd857722}, - {0x00009e5c, 0xe9198724}, - {0x00009fc0, 0x803e4788}, - {0x00009fc4, 0x0001efb5}, - {0x00009fcc, 0x40000014}, - {0x00009fd0, 0x0a193b93}, - {0x0000a20c, 0x00000000}, - {0x0000a220, 0x00000000}, - {0x0000a224, 0x00000000}, - {0x0000a228, 0x10002310}, - {0x0000a23c, 0x00000000}, - {0x0000a244, 0x0c000000}, - {0x0000a2a0, 0x00000001}, - {0x0000a2c0, 0x00000001}, - {0x0000a2c8, 0x00000000}, - {0x0000a2cc, 0x18c43433}, - {0x0000a2d4, 0x00000000}, - {0x0000a2ec, 0x00000000}, - {0x0000a2f0, 0x00000000}, - {0x0000a2f4, 0x00000000}, - {0x0000a2f8, 0x00000000}, - {0x0000a344, 0x00000000}, - {0x0000a34c, 0x00000000}, - {0x0000a350, 0x0000a000}, - {0x0000a364, 0x00000000}, - {0x0000a370, 0x00000000}, - {0x0000a390, 0x00000001}, - {0x0000a394, 0x00000444}, - {0x0000a398, 0x001f0e0f}, - {0x0000a39c, 0x0075393f}, - {0x0000a3a0, 0xb79f6427}, - {0x0000a3c0, 0x20202020}, - {0x0000a3c4, 0x22222220}, - {0x0000a3c8, 0x20200020}, - {0x0000a3cc, 0x20202020}, - {0x0000a3d0, 0x20202020}, - {0x0000a3d4, 0x20202020}, - {0x0000a3d8, 0x20202020}, - {0x0000a3dc, 0x20202020}, - {0x0000a3e0, 0x20202020}, - {0x0000a3e4, 0x20202020}, - {0x0000a3e8, 0x20202020}, - {0x0000a3ec, 0x20202020}, - {0x0000a3f0, 0x00000000}, - {0x0000a3f4, 0x00000006}, - {0x0000a3f8, 0x0c9bd380}, - {0x0000a3fc, 0x000f0f01}, - {0x0000a400, 0x8fa91f01}, - {0x0000a404, 0x00000000}, - {0x0000a408, 0x0e79e5c6}, - {0x0000a40c, 0x00820820}, - {0x0000a414, 0x1ce739ce}, - {0x0000a418, 0x2d001dce}, - {0x0000a434, 0x00000000}, - {0x0000a438, 0x00001801}, - {0x0000a43c, 0x00100000}, - {0x0000a444, 0x00000000}, - {0x0000a448, 0x05000080}, - {0x0000a44c, 0x00000001}, - {0x0000a450, 0x00010000}, - {0x0000a454, 0x07000000}, - {0x0000a644, 0xbfad9d74}, - {0x0000a648, 0x0048060a}, - {0x0000a64c, 0x00002037}, - {0x0000a670, 0x03020100}, - {0x0000a674, 0x09080504}, - {0x0000a678, 0x0d0c0b0a}, - {0x0000a67c, 0x13121110}, - {0x0000a680, 0x31301514}, - {0x0000a684, 0x35343332}, - {0x0000a688, 0x00000036}, - {0x0000a690, 0x00000838}, - {0x0000a6b0, 0x0000000a}, - {0x0000a6b4, 0x00512c01}, - {0x0000a7c0, 0x00000000}, - {0x0000a7c4, 0xfffffffc}, - {0x0000a7c8, 0x00000000}, - {0x0000a7cc, 0x00000000}, - {0x0000a7d0, 0x00000000}, - {0x0000a7d4, 0x00000004}, - {0x0000a7dc, 0x00000000}, - {0x0000a7f0, 0x80000000}, - {0x0000a8d0, 0x004b6a8e}, - {0x0000a8d4, 0x00000820}, - {0x0000a8dc, 0x00000000}, - {0x0000a8f0, 0x00000000}, - {0x0000a8f4, 0x00000000}, - {0x0000abf0, 0x80000000}, - {0x0000b2d0, 0x00000080}, - {0x0000b2d4, 0x00000000}, - {0x0000b2ec, 0x00000000}, - {0x0000b2f0, 0x00000000}, - {0x0000b2f4, 0x00000000}, - {0x0000b2f8, 0x00000000}, - {0x0000b408, 0x0e79e5c0}, - {0x0000b40c, 0x00820820}, - {0x0000b420, 0x00000000}, - {0x0000b6b0, 0x0000000a}, - {0x0000b6b4, 0x00000001}, -}; - static const u32 ar9462_2p1_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d}, @@ -361,9 +237,9 @@ static const u32 ar9462_2p1_baseband_postamble[][5] = { {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e}, {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, - {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e20, 0x000003a5, 0x000003a5, 0x000003a5, 0x000003a5}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c780, 0xcfd5c280}, {0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -383,7 +259,7 @@ static const u32 ar9462_2p1_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -400,1375 +276,16 @@ static const u32 ar9462_2p1_baseband_postamble[][5] = { {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000}, {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, - {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000ae20, 0x000001a6, 0x000001a6, 0x000001aa, 0x000001aa}, {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, }; -static const u32 ar9462_2p1_radio_core[][2] = { - /* Addr allmodes */ - {0x00016000, 0x36db6db6}, - {0x00016004, 0x6db6db40}, - {0x00016008, 0x73f00000}, - {0x0001600c, 0x00000000}, - {0x00016010, 0x6d820001}, - {0x00016040, 0x7f80fff8}, - {0x0001604c, 0x2699e04f}, - {0x00016050, 0x6db6db6c}, - {0x00016058, 0x6c200000}, - {0x00016080, 0x000c0000}, - {0x00016084, 0x9a68048c}, - {0x00016088, 0x54214514}, - {0x0001608c, 0x1203040b}, - {0x00016090, 0x24926490}, - {0x00016098, 0xd2888888}, - {0x000160a0, 0x0a108ffe}, - {0x000160a4, 0x812fc491}, - {0x000160a8, 0x423c8000}, - {0x000160b4, 0x92000000}, - {0x000160b8, 0x0285dddc}, - {0x000160bc, 0x02908888}, - {0x000160c0, 0x00adb6d0}, - {0x000160c4, 0x6db6db60}, - {0x000160c8, 0x6db6db6c}, - {0x000160cc, 0x0de6c1b0}, - {0x00016100, 0x3fffbe04}, - {0x00016104, 0xfff80000}, - {0x00016108, 0x00200400}, - {0x00016110, 0x00000000}, - {0x00016144, 0x02084080}, - {0x00016148, 0x000080c0}, - {0x00016280, 0x050a0001}, - {0x00016284, 0x3d841418}, - {0x00016288, 0x00000000}, - {0x0001628c, 0xe3000000}, - {0x00016290, 0xa1005080}, - {0x00016294, 0x00000020}, - {0x00016298, 0x54a82900}, - {0x00016340, 0x121e4276}, - {0x00016344, 0x00300000}, - {0x00016400, 0x36db6db6}, - {0x00016404, 0x6db6db40}, - {0x00016408, 0x73f00000}, - {0x0001640c, 0x00000000}, - {0x00016410, 0x6c800001}, - {0x00016440, 0x7f80fff8}, - {0x0001644c, 0x4699e04f}, - {0x00016450, 0x6db6db6c}, - {0x00016500, 0x3fffbe04}, - {0x00016504, 0xfff80000}, - {0x00016508, 0x00200400}, - {0x00016510, 0x00000000}, - {0x00016544, 0x02084080}, - {0x00016548, 0x000080c0}, -}; - -static const u32 ar9462_2p1_radio_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524}, - {0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70}, - {0x0001610c, 0x48000000, 0x40000000, 0x40000000, 0x40000000}, - {0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000}, -}; - static const u32 ar9462_2p1_soc_preamble[][2] = { /* Addr allmodes */ - {0x000040a4, 0x00a0c1c9}, + {0x000040a4, 0x00a0c9c9}, {0x00007020, 0x00000000}, {0x00007034, 0x00000002}, {0x00007038, 0x000004c2}, }; -static const u32 ar9462_2p1_soc_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00007010, 0x00000033, 0x00000033, 0x00000033, 0x00000033}, -}; - -static const u32 ar9462_2p1_radio_postamble_sys2ant[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808}, - {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, - {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, -}; - -static const u32 ar9462_2p1_common_rx_gain[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x01910190}, - {0x0000a030, 0x01930192}, - {0x0000a034, 0x01950194}, - {0x0000a038, 0x038a0196}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x22222229}, - {0x0000a084, 0x1d1d1d1d}, - {0x0000a088, 0x1d1d1d1d}, - {0x0000a08c, 0x1d1d1d1d}, - {0x0000a090, 0x171d1d1d}, - {0x0000a094, 0x11111717}, - {0x0000a098, 0x00030311}, - {0x0000a09c, 0x00000000}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x2a2d2f32}, - {0x0000b084, 0x21232328}, - {0x0000b088, 0x19191c1e}, - {0x0000b08c, 0x12141417}, - {0x0000b090, 0x07070e0e}, - {0x0000b094, 0x03030305}, - {0x0000b098, 0x00000003}, - {0x0000b09c, 0x00000000}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p1_common_mixed_rx_gain[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x2a2d2f32}, - {0x0000b084, 0x21232328}, - {0x0000b088, 0x19191c1e}, - {0x0000b08c, 0x12141417}, - {0x0000b090, 0x07070e0e}, - {0x0000b094, 0x03030305}, - {0x0000b098, 0x00000003}, - {0x0000b09c, 0x00000000}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p1_baseband_core_mix_rxgain[][2] = { - /* Addr allmodes */ - {0x00009fd0, 0x0a2d6b93}, -}; - -static const u32 ar9462_2p1_baseband_postamble_mix_rxgain[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae}, - {0x00009824, 0x63c640de, 0x5ac640d0, 0x63c640da, 0x63c640da}, - {0x00009828, 0x0796be89, 0x0696b081, 0x0916be81, 0x0916be81}, - {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000d8, 0x6c4000d8}, - {0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec86d2e, 0x7ec86d2e}, - {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32395c5e}, -}; - -static const u32 ar9462_2p1_baseband_postamble_5g_xlna[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282}, -}; - -static const u32 ar9462_2p1_common_wo_xlna_rx_gain[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x32323232}, - {0x0000b084, 0x2f2f3232}, - {0x0000b088, 0x23282a2d}, - {0x0000b08c, 0x1c1e2123}, - {0x0000b090, 0x14171919}, - {0x0000b094, 0x0e0e1214}, - {0x0000b098, 0x03050707}, - {0x0000b09c, 0x00030303}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p1_common_5g_xlna_only_rx_gain[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x2a2d2f32}, - {0x0000b084, 0x21232328}, - {0x0000b088, 0x19191c1e}, - {0x0000b08c, 0x12141417}, - {0x0000b090, 0x07070e0e}, - {0x0000b094, 0x03030305}, - {0x0000b098, 0x00000003}, - {0x0000b09c, 0x00000000}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - -static const u32 ar9462_2p1_modes_low_ob_db_tx_gain[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, - {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, - {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, - {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, - {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, - {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, - {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, - {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, - {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, - {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, - {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, - {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, - {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, - {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, - {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, - {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, - {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, - {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, - {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, - {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x00016044, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, - {0x00016048, 0x64992060, 0x64992060, 0x64992060, 0x64992060}, - {0x00016054, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, - {0x00016444, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, - {0x00016448, 0x64992000, 0x64992000, 0x64992000, 0x64992000}, - {0x00016454, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, -}; - -static const u32 ar9462_2p1_modes_high_ob_db_tx_gain[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, - {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050da, 0x000050da, 0x000050de, 0x000050de}, - {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, - {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002}, - {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004}, - {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400}, - {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402}, - {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404}, - {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603}, - {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02}, - {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04}, - {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20}, - {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20}, - {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22}, - {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24}, - {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640}, - {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660}, - {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861}, - {0x0000a548, 0x55025eb3, 0x55025eb3, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x58025ef3, 0x58025ef3, 0x42001a83, 0x42001a83}, - {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001a84, 0x44001a84}, - {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3}, - {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5}, - {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9}, - {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb}, - {0x0000a564, 0x751ffff6, 0x751ffff6, 0x56001eec, 0x56001eec}, - {0x0000a568, 0x751ffff6, 0x751ffff6, 0x58001ef0, 0x58001ef0}, - {0x0000a56c, 0x751ffff6, 0x751ffff6, 0x5a001ef4, 0x5a001ef4}, - {0x0000a570, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6}, - {0x0000a574, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6}, - {0x0000a578, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6}, - {0x0000a57c, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, - {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, - {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, - {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, - {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x00016044, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4}, - {0x00016048, 0x8db49060, 0x8db49060, 0x8db49060, 0x8db49060}, - {0x00016054, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, - {0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4}, - {0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000}, - {0x00016454, 0x6db60000, 0x6db60000, 0x6db60000, 0x6db60000}, -}; - -static const u32 ar9462_2p1_modes_mix_ob_db_tx_gain[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, - {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x0000d0da, 0x0000d0da, 0x0000d0de, 0x0000d0de}, - {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, - {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002}, - {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004}, - {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x18022622, 0x18022622, 0x12000400, 0x12000400}, - {0x0000a518, 0x1b022822, 0x1b022822, 0x16000402, 0x16000402}, - {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404}, - {0x0000a520, 0x22022c41, 0x22022c41, 0x1c000603, 0x1c000603}, - {0x0000a524, 0x28023042, 0x28023042, 0x21000a02, 0x21000a02}, - {0x0000a528, 0x2c023044, 0x2c023044, 0x25000a04, 0x25000a04}, - {0x0000a52c, 0x2f023644, 0x2f023644, 0x28000a20, 0x28000a20}, - {0x0000a530, 0x34025643, 0x34025643, 0x2c000e20, 0x2c000e20}, - {0x0000a534, 0x38025a44, 0x38025a44, 0x30000e22, 0x30000e22}, - {0x0000a538, 0x3b025e45, 0x3b025e45, 0x34000e24, 0x34000e24}, - {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x38001640, 0x38001640}, - {0x0000a540, 0x48025e6c, 0x48025e6c, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x55025eb3, 0x55025eb3, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x58025ef3, 0x58025ef3, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x62025f56, 0x62025f56, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x66027f56, 0x66027f56, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x70049f56, 0x70049f56, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x751ffff6, 0x751ffff6, 0x5c001eec, 0x5c001eec}, - {0x0000a568, 0x751ffff6, 0x751ffff6, 0x5e001ef0, 0x5e001ef0}, - {0x0000a56c, 0x751ffff6, 0x751ffff6, 0x60001ef4, 0x60001ef4}, - {0x0000a570, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6}, - {0x0000a574, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6}, - {0x0000a578, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6}, - {0x0000a57c, 0x751ffff6, 0x751ffff6, 0x62001ff6, 0x62001ff6}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, - {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, - {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, - {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, - {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, -}; - -static const u32 ar9462_2p1_modes_fast_clock[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x00001030, 0x00000268, 0x000004d0}, - {0x00001070, 0x0000018c, 0x00000318}, - {0x000010b0, 0x00000fd0, 0x00001fa0}, - {0x00008014, 0x044c044c, 0x08980898}, - {0x0000801c, 0x148ec02b, 0x148ec057}, - {0x00008318, 0x000044c0, 0x00008980}, - {0x00009e00, 0x0372131c, 0x0372131c}, - {0x0000a230, 0x0000400b, 0x00004016}, - {0x0000a254, 0x00000898, 0x00001130}, -}; - -static const u32 ar9462_2p1_baseband_core_txfir_coeff_japan_2484[][2] = { - /* Addr allmodes */ - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x6f7f0301}, - {0x0000a3a0, 0xca9228ee}, -}; - #endif /* INITVALS_9462_2P1_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index 88ff1d7b53ab..4afe52c0456e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -20,20 +20,18 @@ /* AR9485 1.1 */ -#define ar9485_1_1_mac_postamble ar9300_2p2_mac_postamble +#define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1 -static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x18012e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000080c}, -}; +#define ar9485_1_1_mac_postamble ar9331_1p1_mac_postamble + +#define ar9485_1_1_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = { /* Addr allmodes */ {0x00009e00, 0x037216a0}, {0x00009e04, 0x00182020}, {0x00009e18, 0x00000000}, + {0x00009e20, 0x000003a8}, {0x00009e2c, 0x00004121}, {0x00009e44, 0x02282324}, {0x0000a000, 0x00060005}, @@ -174,7 +172,7 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { {0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, {0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, {0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050da, 0x000050da}, {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, @@ -200,14 +198,14 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x62001eee, 0x62001eee}, + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x66001ff6, 0x66001ff6}, + {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, + {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, + {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, + {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, + {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, + {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -263,6 +261,11 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { static const u32 ar9485Modes_green_ob_db_tx_gain_1_1[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a}, + {0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, + {0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000}, {0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006}, @@ -297,6 +300,22 @@ static const u32 ar9485Modes_green_ob_db_tx_gain_1_1[][5] = { {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501}, + {0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803}, + {0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04}, + {0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, + {0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305}, {0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, {0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, {0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, @@ -341,7 +360,7 @@ static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = { {0x0000a2e0, 0x00000000, 0x00000000, 0xffc63a84, 0xffc63a84}, {0x0000a2e4, 0x00000000, 0x00000000, 0xfe0fc000, 0xfe0fc000}, {0x0000a2e8, 0x00000000, 0x00000000, 0xfff00000, 0xfff00000}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050da, 0x000050da}, {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, @@ -367,14 +386,14 @@ static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = { {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x62001eee, 0x62001eee}, + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x66001ff6, 0x66001ff6}, + {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, + {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, + {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, + {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, + {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, + {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6}, {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -521,12 +540,15 @@ static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = { {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, }; -#define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1 - static const u32 ar9485Modes_green_spur_ob_db_tx_gain_1_1[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a}, + {0x0000a2dc, 0x00000000, 0x00000000, 0xffad452a, 0xffad452a}, + {0x0000a2e0, 0x00000000, 0x00000000, 0xffc98634, 0xffc98634}, + {0x0000a2e4, 0x00000000, 0x00000000, 0xfff60780, 0xfff60780}, + {0x0000a2e8, 0x00000000, 0x00000000, 0xfffff800, 0xfffff800}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000}, {0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006}, {0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201}, @@ -543,23 +565,39 @@ static const u32 ar9485Modes_green_spur_ob_db_tx_gain_1_1[][5] = { {0x0000a530, 0x48023ec6, 0x48023ec6, 0x310006e0, 0x310006e0}, {0x0000a534, 0x4d023f01, 0x4d023f01, 0x330006e0, 0x330006e0}, {0x0000a538, 0x53023f4b, 0x53023f4b, 0x3e0008e3, 0x3e0008e3}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x410008e5, 0x410008e5}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x430008e6, 0x430008e6}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x4a0008ec, 0x4a0008ec}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4e0008f1, 0x4e0008f1}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x520008f3, 0x520008f3}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x54000eed, 0x54000eed}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x58000ef1, 0x58000ef1}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5c000ef3, 0x5c000ef3}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x60000ef5, 0x60000ef5}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x62000ef6, 0x62000ef6}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x62000ef6, 0x62000ef6}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6}, + {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x430008e6, 0x430008e6}, + {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x4a0008ec, 0x4a0008ec}, + {0x0000a544, 0x6502feca, 0x6502feca, 0x4e0008f1, 0x4e0008f1}, + {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x520008f3, 0x520008f3}, + {0x0000a54c, 0x7203feca, 0x7203feca, 0x54000eed, 0x54000eed}, + {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x58000ef1, 0x58000ef1}, + {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x5c000ef3, 0x5c000ef3}, + {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x62000ef6, 0x62000ef6}, + {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x66001ff0, 0x66001ff0}, + {0x0000a560, 0x900fff0b, 0x900fff0b, 0x68001ff6, 0x68001ff6}, + {0x0000a564, 0x960fffcb, 0x960fffcb, 0x68001ff6, 0x68001ff6}, + {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6}, + {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6}, + {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6}, + {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6}, + {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6}, + {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6}, + {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a58c, 0x00000000, 0x00000000, 0x01804000, 0x01804000}, + {0x0000a590, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02}, + {0x0000a594, 0x00000000, 0x00000000, 0x0340ca02, 0x0340ca02}, + {0x0000a598, 0x00000000, 0x00000000, 0x0340cd03, 0x0340cd03}, + {0x0000a59c, 0x00000000, 0x00000000, 0x0340cd03, 0x0340cd03}, + {0x0000a5a0, 0x00000000, 0x00000000, 0x06415304, 0x06415304}, + {0x0000a5a4, 0x00000000, 0x00000000, 0x04c11905, 0x04c11905}, + {0x0000a5a8, 0x00000000, 0x00000000, 0x06415905, 0x06415905}, + {0x0000a5ac, 0x00000000, 0x00000000, 0x06415905, 0x06415905}, + {0x0000a5b0, 0x00000000, 0x00000000, 0x06415905, 0x06415905}, + {0x0000a5b4, 0x00000000, 0x00000000, 0x06415905, 0x06415905}, + {0x0000a5b8, 0x00000000, 0x00000000, 0x06415905, 0x06415905}, + {0x0000a5bc, 0x00000000, 0x00000000, 0x06415905, 0x06415905}, {0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, {0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, {0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, @@ -823,6 +861,7 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = { {0x00009e00, 0x03721b20}, {0x00009e04, 0x00082020}, {0x00009e18, 0x0300501e}, + {0x00009e20, 0x000003ba}, {0x00009e2c, 0x00002e21}, {0x00009e44, 0x02182324}, {0x0000a000, 0x00060005}, @@ -955,20 +994,6 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = { {0x0000a1fc, 0x00000296}, }; -static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_enable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x18052e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000080c}, -}; - -static const u32 ar9485_1_1_pcie_phy_clkreq_enable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x18053e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000080c}, -}; - static const u32 ar9485_1_1_soc_preamble[][2] = { /* Addr allmodes */ {0x00004014, 0xba280400}, @@ -981,13 +1006,6 @@ static const u32 ar9485_1_1_soc_preamble[][2] = { {0x00007048, 0x00000002}, }; -static const u32 ar9485_fast_clock_1_1_baseband_postamble[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x00009e00, 0x03721821, 0x03721821}, - {0x0000a230, 0x0000400b, 0x00004016}, - {0x0000a254, 0x00000898, 0x00001130}, -}; - static const u32 ar9485_1_1_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, @@ -1001,8 +1019,7 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = { {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e}, {0x00009e14, 0x31395d53, 0x31396053, 0x312e6053, 0x312e5d53}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, - {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946220, 0xcf946220}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0}, @@ -1020,7 +1037,7 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0}, {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, {0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982}, {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -1028,13 +1045,6 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = { {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, }; -static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x18013e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000080c}, -}; - static const u32 ar9485_1_1_radio_postamble[][2] = { /* Addr allmodes */ {0x0001609c, 0x0b283f31}, @@ -1206,6 +1216,18 @@ static const u32 ar9485_1_1_mac_core[][2] = { {0x000083d0, 0x000301ff}, }; -#define ar9485_1_1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 +static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x18013e5e}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0000080c}, +}; + +static const u32 ar9485_1_1_pll_on_cdr_on_clkreq_disable_L1[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x1801265e}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0000080c}, +}; #endif /* INITVALS_9485_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h new file mode 100644 index 000000000000..924ae6bde7f1 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h @@ -0,0 +1,1420 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INITVALS_953X_H +#define INITVALS_953X_H + +#define qca953x_1p0_mac_postamble ar9300_2p2_mac_postamble + +#define qca953x_1p0_soc_preamble ar955x_1p0_soc_preamble + +#define qca953x_1p0_soc_postamble ar9300_2p2_soc_postamble + +#define qca953x_1p0_common_rx_gain_table ar9300Common_rx_gain_table_2p2 + +#define qca953x_1p0_common_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define qca953x_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2 + +#define qca953x_1p0_common_wo_xlna_rx_gain_bounds ar955x_1p0_common_wo_xlna_rx_gain_bounds + +#define qca953x_1p0_common_rx_gain_bounds ar955x_1p0_common_rx_gain_bounds + +static const u32 qca953x_1p0_mac_core[][2] = { + /* Addr allmodes */ + {0x00000008, 0x00000000}, + {0x00000030, 0x00020085}, + {0x00000034, 0x00000005}, + {0x00000040, 0x00000000}, + {0x00000044, 0x00000000}, + {0x00000048, 0x00000008}, + {0x0000004c, 0x00000010}, + {0x00000050, 0x00000000}, + {0x00001040, 0x002ffc0f}, + {0x00001044, 0x002ffc0f}, + {0x00001048, 0x002ffc0f}, + {0x0000104c, 0x002ffc0f}, + {0x00001050, 0x002ffc0f}, + {0x00001054, 0x002ffc0f}, + {0x00001058, 0x002ffc0f}, + {0x0000105c, 0x002ffc0f}, + {0x00001060, 0x002ffc0f}, + {0x00001064, 0x002ffc0f}, + {0x000010f0, 0x00000100}, + {0x00001270, 0x00000000}, + {0x000012b0, 0x00000000}, + {0x000012f0, 0x00000000}, + {0x0000143c, 0x00000000}, + {0x0000147c, 0x00000000}, + {0x00008000, 0x00000000}, + {0x00008004, 0x00000000}, + {0x00008008, 0x00000000}, + {0x0000800c, 0x00000000}, + {0x00008018, 0x00000000}, + {0x00008020, 0x00000000}, + {0x00008038, 0x00000000}, + {0x0000803c, 0x00000000}, + {0x00008040, 0x00000000}, + {0x00008044, 0x00000000}, + {0x00008048, 0x00000000}, + {0x0000804c, 0xffffffff}, + {0x00008054, 0x00000000}, + {0x00008058, 0x00000000}, + {0x0000805c, 0x000fc78f}, + {0x00008060, 0x0000000f}, + {0x00008064, 0x00000000}, + {0x00008070, 0x00000310}, + {0x00008074, 0x00000020}, + {0x00008078, 0x00000000}, + {0x0000809c, 0x0000000f}, + {0x000080a0, 0x00000000}, + {0x000080a4, 0x02ff0000}, + {0x000080a8, 0x0e070605}, + {0x000080ac, 0x0000000d}, + {0x000080b0, 0x00000000}, + {0x000080b4, 0x00000000}, + {0x000080b8, 0x00000000}, + {0x000080bc, 0x00000000}, + {0x000080c0, 0x2a800000}, + {0x000080c4, 0x06900168}, + {0x000080c8, 0x13881c22}, + {0x000080cc, 0x01f40000}, + {0x000080d0, 0x00252500}, + {0x000080d4, 0x00a00000}, + {0x000080d8, 0x00400000}, + {0x000080dc, 0x00000000}, + {0x000080e0, 0xffffffff}, + {0x000080e4, 0x0000ffff}, + {0x000080e8, 0x3f3f3f3f}, + {0x000080ec, 0x00000000}, + {0x000080f0, 0x00000000}, + {0x000080f4, 0x00000000}, + {0x000080fc, 0x00020000}, + {0x00008100, 0x00000000}, + {0x00008108, 0x00000052}, + {0x0000810c, 0x00000000}, + {0x00008110, 0x00000000}, + {0x00008114, 0x000007ff}, + {0x00008118, 0x000000aa}, + {0x0000811c, 0x00003210}, + {0x00008124, 0x00000000}, + {0x00008128, 0x00000000}, + {0x0000812c, 0x00000000}, + {0x00008130, 0x00000000}, + {0x00008134, 0x00000000}, + {0x00008138, 0x00000000}, + {0x0000813c, 0x0000ffff}, + {0x00008140, 0x000000fe}, + {0x00008144, 0xffffffff}, + {0x00008168, 0x00000000}, + {0x0000816c, 0x00000000}, + {0x000081c0, 0x00000000}, + {0x000081c4, 0x33332210}, + {0x000081ec, 0x00000000}, + {0x000081f0, 0x00000000}, + {0x000081f4, 0x00000000}, + {0x000081f8, 0x00000000}, + {0x000081fc, 0x00000000}, + {0x00008240, 0x00100000}, + {0x00008244, 0x0010f3d7}, + {0x00008248, 0x00000852}, + {0x0000824c, 0x0001e7ae}, + {0x00008250, 0x00000000}, + {0x00008254, 0x00000000}, + {0x00008258, 0x00000000}, + {0x0000825c, 0x40000000}, + {0x00008260, 0x00080922}, + {0x00008264, 0x9d400010}, + {0x00008268, 0xffffffff}, + {0x0000826c, 0x0000ffff}, + {0x00008270, 0x00000000}, + {0x00008274, 0x40000000}, + {0x00008278, 0x003e4180}, + {0x0000827c, 0x00000004}, + {0x00008284, 0x0000002c}, + {0x00008288, 0x0000002c}, + {0x0000828c, 0x000000ff}, + {0x00008294, 0x00000000}, + {0x00008298, 0x00000000}, + {0x0000829c, 0x00000000}, + {0x00008300, 0x00001d40}, + {0x00008314, 0x00000000}, + {0x0000831c, 0x0000010d}, + {0x00008328, 0x00000000}, + {0x0000832c, 0x0000001f}, + {0x00008330, 0x00000302}, + {0x00008334, 0x00000700}, + {0x00008338, 0xffff0000}, + {0x0000833c, 0x02400000}, + {0x00008340, 0x000107ff}, + {0x00008344, 0xaa48107b}, + {0x00008348, 0x008f0000}, + {0x0000835c, 0x00000000}, + {0x00008360, 0xffffffff}, + {0x00008364, 0xffffffff}, + {0x00008368, 0x00000000}, + {0x00008370, 0x00000000}, + {0x00008374, 0x000000ff}, + {0x00008378, 0x00000000}, + {0x0000837c, 0x00000000}, + {0x00008380, 0xffffffff}, + {0x00008384, 0xffffffff}, + {0x00008390, 0xffffffff}, + {0x00008394, 0xffffffff}, + {0x00008398, 0x00000000}, + {0x0000839c, 0x00000000}, + {0x000083a0, 0x00000000}, + {0x000083a4, 0x0000fa14}, + {0x000083a8, 0x000f0c00}, + {0x000083ac, 0x33332210}, + {0x000083b0, 0x33332210}, + {0x000083b4, 0x33332210}, + {0x000083b8, 0x33332210}, + {0x000083bc, 0x00000000}, + {0x000083c0, 0x00000000}, + {0x000083c4, 0x00000000}, + {0x000083c8, 0x00000000}, + {0x000083cc, 0x00000200}, + {0x000083d0, 0x8c7901ff}, +}; + +static const u32 qca953x_1p0_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a9f6b}, + {0x0000980c, 0x04900000}, + {0x00009814, 0x0280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x6400a190}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14000600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x32840bbe}, + {0x000098bc, 0x00000002}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x9883800a}, + {0x00009d10, 0x018848c6}, + {0x00009d14, 0x00c0040b}, + {0x00009d18, 0x00000000}, + {0x00009e08, 0x0038230c}, + {0x00009e24, 0x990bb515}, + {0x00009e28, 0x0c6f0000}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009fc0, 0x813e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x01193b91}, + {0x0000a20c, 0x00000000}, + {0x0000a220, 0x00000000}, + {0x0000a224, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a248, 0x00000140}, + {0x0000a2a0, 0x00000007}, + {0x0000a2c0, 0x00000007}, + {0x0000a2c8, 0x00000000}, + {0x0000a2d4, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a364, 0x00000000}, + {0x0000a370, 0x00000000}, + {0x0000a390, 0x00000001}, + {0x0000a394, 0x00000444}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, + {0x0000a3a4, 0x000000ff}, + {0x0000a3a8, 0x6a6a6a6a}, + {0x0000a3ac, 0x6a6a6a6a}, + {0x0000a3b0, 0x00c8641a}, + {0x0000a3b4, 0x0000001a}, + {0x0000a3b8, 0x0088642a}, + {0x0000a3bc, 0x000001fa}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000000}, + {0x0000a3f8, 0x0c9bd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce42108}, + {0x0000a418, 0x2d001dce}, + {0x0000a41c, 0x1ce73908}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce738e7}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00100000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x05000080}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a458, 0x00000000}, + {0x0000a644, 0xbfad9d74}, + {0x0000a648, 0x0048060a}, + {0x0000a64c, 0x00003c37}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x09080504}, + {0x0000a678, 0x0d0c0b0a}, + {0x0000a67c, 0x13121110}, + {0x0000a680, 0x31301514}, + {0x0000a684, 0x35343332}, + {0x0000a688, 0x00000036}, + {0x0000a690, 0x08000838}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000000}, + {0x0000a8d0, 0x004b6a8e}, + {0x0000a8d4, 0x00000820}, + {0x0000a8dc, 0x00000000}, + {0x0000a8f0, 0x00000000}, + {0x0000a8f4, 0x00000000}, + {0x0000b2d0, 0x00000080}, + {0x0000b2d4, 0x00000000}, + {0x0000b2ec, 0x00000000}, + {0x0000b2f0, 0x00000000}, + {0x0000b2f4, 0x00000000}, + {0x0000b2f8, 0x00000000}, + {0x0000b408, 0x0e79e5c0}, + {0x0000b40c, 0x00820820}, + {0x0000b420, 0x00000000}, +}; + +static const u32 qca953x_1p0_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, + {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, + {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10820, 0xcfa10820}, + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f}, + {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, + {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e}, + {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, + {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, + {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18}, + {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, + {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, + {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, +}; + +static const u32 qca953x_1p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db6db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016040, 0x3f80fff8}, + {0x0001604c, 0x000f0278}, + {0x00016050, 0x8036db6c}, + {0x00016054, 0x6db60000}, + {0x00016080, 0x00080000}, + {0x00016084, 0x0e48048c}, + {0x00016088, 0x14214514}, + {0x0001608c, 0x119f080a}, + {0x00016090, 0x24926490}, + {0x00016094, 0x00000000}, + {0x000160a0, 0xc2108ffe}, + {0x000160a4, 0x812fc370}, + {0x000160a8, 0x423c8000}, + {0x000160b4, 0x92480080}, + {0x000160c0, 0x006db6d8}, + {0x000160c4, 0x24b6db6c}, + {0x000160c8, 0x6db6db6c}, + {0x000160cc, 0x6db6fb7c}, + {0x000160d0, 0x6db6da44}, + {0x00016100, 0x07ff8001}, + {0x00016108, 0x00080010}, + {0x00016144, 0x01884080}, + {0x00016148, 0x000080d8}, + {0x00016280, 0x01000901}, + {0x00016284, 0x15d30000}, + {0x00016288, 0x00318000}, + {0x0001628c, 0x50000000}, + {0x00016380, 0x00000000}, + {0x00016384, 0x00000000}, + {0x00016388, 0x00800700}, + {0x0001638c, 0x00800700}, + {0x00016390, 0x00800700}, + {0x00016394, 0x00000000}, + {0x00016398, 0x00000000}, + {0x0001639c, 0x00000000}, + {0x000163a0, 0x00000001}, + {0x000163a4, 0x00000001}, + {0x000163a8, 0x00000000}, + {0x000163ac, 0x00000000}, + {0x000163b0, 0x00000000}, + {0x000163b4, 0x00000000}, + {0x000163b8, 0x00000000}, + {0x000163bc, 0x00000000}, + {0x000163c0, 0x000000a0}, + {0x000163c4, 0x000c0000}, + {0x000163c8, 0x14021402}, + {0x000163cc, 0x00001402}, + {0x000163d0, 0x00000000}, + {0x000163d4, 0x00000000}, + {0x00016400, 0x36db6db6}, + {0x00016404, 0x6db6db40}, + {0x00016408, 0x73f00000}, + {0x0001640c, 0x00000000}, + {0x00016440, 0x3f80fff8}, + {0x0001644c, 0x000f0278}, + {0x00016450, 0x8036db6c}, + {0x00016454, 0x6db60000}, + {0x00016500, 0x07ff8001}, + {0x00016508, 0x00080010}, + {0x00016544, 0x01884080}, + {0x00016548, 0x000080d8}, + {0x00016780, 0x00000000}, + {0x00016784, 0x00000000}, + {0x00016788, 0x00800700}, + {0x0001678c, 0x00800700}, + {0x00016790, 0x00800700}, + {0x00016794, 0x00000000}, + {0x00016798, 0x00000000}, + {0x0001679c, 0x00000000}, + {0x000167a0, 0x00000001}, + {0x000167a4, 0x00000001}, + {0x000167a8, 0x00000000}, + {0x000167ac, 0x00000000}, + {0x000167b0, 0x00000000}, + {0x000167b4, 0x00000000}, + {0x000167b8, 0x00000000}, + {0x000167bc, 0x00000000}, + {0x000167c0, 0x000000a0}, + {0x000167c4, 0x000c0000}, + {0x000167c8, 0x14021402}, + {0x000167cc, 0x00001402}, + {0x000167d0, 0x00000000}, + {0x000167d4, 0x00000000}, +}; + +static const u32 qca953x_1p0_radio_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xc4128f5c, 0xc4128f5c}, + {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0fd08f25, 0x0fd08f25}, + {0x000160ac, 0xa4647c00, 0xa4647c00, 0x24646800, 0x24646800}, + {0x000160b0, 0x01885f52, 0x01885f52, 0x00fe7f46, 0x00fe7f46}, + {0x00016104, 0xb7a00001, 0xb7a00001, 0xfff80005, 0xfff80005}, + {0x0001610c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, + {0x00016140, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, + {0x00016504, 0xb7a00001, 0xb7a00001, 0xfff80001, 0xfff80001}, + {0x0001650c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, + {0x00016540, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, +}; + +static const u32 qca953x_1p0_modes_xpa_tx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a2dc, 0xfffd5aaa}, + {0x0000a2e0, 0xfffe9ccc}, + {0x0000a2e4, 0xffffe0f0}, + {0x0000a2e8, 0xfffcff00}, + {0x0000a410, 0x000050da}, + {0x0000a500, 0x00000000}, + {0x0000a504, 0x04000002}, + {0x0000a508, 0x08000004}, + {0x0000a50c, 0x0c000006}, + {0x0000a510, 0x0f00000a}, + {0x0000a514, 0x1300000c}, + {0x0000a518, 0x1700000e}, + {0x0000a51c, 0x1b000064}, + {0x0000a520, 0x1f000242}, + {0x0000a524, 0x23000229}, + {0x0000a528, 0x270002a2}, + {0x0000a52c, 0x2c001203}, + {0x0000a530, 0x30001803}, + {0x0000a534, 0x33000881}, + {0x0000a538, 0x38001809}, + {0x0000a53c, 0x3a000814}, + {0x0000a540, 0x3f001a0c}, + {0x0000a544, 0x43001a0e}, + {0x0000a548, 0x46001812}, + {0x0000a54c, 0x49001884}, + {0x0000a550, 0x4d001e84}, + {0x0000a554, 0x50001e69}, + {0x0000a558, 0x550006f4}, + {0x0000a55c, 0x59000ad3}, + {0x0000a560, 0x5e000ad5}, + {0x0000a564, 0x61001ced}, + {0x0000a568, 0x660018d4}, + {0x0000a56c, 0x660018d4}, + {0x0000a570, 0x660018d4}, + {0x0000a574, 0x660018d4}, + {0x0000a578, 0x660018d4}, + {0x0000a57c, 0x660018d4}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x03804000}, + {0x0000a610, 0x0300ca02}, + {0x0000a614, 0x00000e04}, + {0x0000a618, 0x03014000}, + {0x0000a61c, 0x00000000}, + {0x0000a620, 0x00000000}, + {0x0000a624, 0x03014000}, + {0x0000a628, 0x03804c05}, + {0x0000a62c, 0x0701de06}, + {0x0000a630, 0x07819c07}, + {0x0000a634, 0x0701dc07}, + {0x0000a638, 0x0701dc07}, + {0x0000a63c, 0x0701dc07}, + {0x0000b2dc, 0xfffd5aaa}, + {0x0000b2e0, 0xfffe9ccc}, + {0x0000b2e4, 0xffffe0f0}, + {0x0000b2e8, 0xfffcff00}, + {0x00016044, 0x010002d4}, + {0x00016048, 0x66482400}, + {0x00016280, 0x01000015}, + {0x00016444, 0x010002d4}, + {0x00016448, 0x66482400}, +}; + +static const u32 qca953x_1p0_modes_no_xpa_tx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a2dc, 0xffd5f552}, + {0x0000a2e0, 0xffe60664}, + {0x0000a2e4, 0xfff80780}, + {0x0000a2e8, 0xfffff800}, + {0x0000a410, 0x000050d6}, + {0x0000a500, 0x00060020}, + {0x0000a504, 0x04060060}, + {0x0000a508, 0x080600a0}, + {0x0000a50c, 0x0c068020}, + {0x0000a510, 0x10068060}, + {0x0000a514, 0x140680a0}, + {0x0000a518, 0x18090040}, + {0x0000a51c, 0x1b090080}, + {0x0000a520, 0x1f0900c0}, + {0x0000a524, 0x240c0041}, + {0x0000a528, 0x280d0021}, + {0x0000a52c, 0x2d0f0061}, + {0x0000a530, 0x310f00a1}, + {0x0000a534, 0x350e00a2}, + {0x0000a538, 0x360e80a2}, + {0x0000a53c, 0x380f00a2}, + {0x0000a540, 0x3b0e00a3}, + {0x0000a544, 0x3d110083}, + {0x0000a548, 0x3e1100a3}, + {0x0000a54c, 0x401100e3}, + {0x0000a550, 0x421380e3}, + {0x0000a554, 0x431780e3}, + {0x0000a558, 0x461f80e3}, + {0x0000a55c, 0x461f80e3}, + {0x0000a560, 0x461f80e3}, + {0x0000a564, 0x461f80e3}, + {0x0000a568, 0x461f80e3}, + {0x0000a56c, 0x461f80e3}, + {0x0000a570, 0x461f80e3}, + {0x0000a574, 0x461f80e3}, + {0x0000a578, 0x461f80e3}, + {0x0000a57c, 0x461f80e3}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x00804201}, + {0x0000a610, 0x01008201}, + {0x0000a614, 0x0180c402}, + {0x0000a618, 0x0180c603}, + {0x0000a61c, 0x0180c603}, + {0x0000a620, 0x01c10603}, + {0x0000a624, 0x01c10704}, + {0x0000a628, 0x02c18b05}, + {0x0000a62c, 0x0301cc07}, + {0x0000a630, 0x0301cc07}, + {0x0000a634, 0x0301cc07}, + {0x0000a638, 0x0301cc07}, + {0x0000a63c, 0x0301cc07}, + {0x0000b2dc, 0xffd5f552}, + {0x0000b2e0, 0xffe60664}, + {0x0000b2e4, 0xfff80780}, + {0x0000b2e8, 0xfffff800}, + {0x00016044, 0x049242db}, + {0x00016048, 0x6c927a70}, + {0x00016444, 0x049242db}, + {0x00016448, 0x6c927a70}, +}; + +static const u32 qca953x_1p1_modes_no_xpa_tx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a2dc, 0xffd5f552}, + {0x0000a2e0, 0xffe60664}, + {0x0000a2e4, 0xfff80780}, + {0x0000a2e8, 0xfffff800}, + {0x0000a410, 0x000050de}, + {0x0000a500, 0x00000061}, + {0x0000a504, 0x04000063}, + {0x0000a508, 0x08000065}, + {0x0000a50c, 0x0c000261}, + {0x0000a510, 0x10000263}, + {0x0000a514, 0x14000265}, + {0x0000a518, 0x18000482}, + {0x0000a51c, 0x1b000484}, + {0x0000a520, 0x1f000486}, + {0x0000a524, 0x240008c2}, + {0x0000a528, 0x28000cc1}, + {0x0000a52c, 0x2d000ce3}, + {0x0000a530, 0x31000ce5}, + {0x0000a534, 0x350010e5}, + {0x0000a538, 0x360012e5}, + {0x0000a53c, 0x380014e5}, + {0x0000a540, 0x3b0018e5}, + {0x0000a544, 0x3d001d04}, + {0x0000a548, 0x3e001d05}, + {0x0000a54c, 0x40001d07}, + {0x0000a550, 0x42001f27}, + {0x0000a554, 0x43001f67}, + {0x0000a558, 0x46001fe7}, + {0x0000a55c, 0x47001f2b}, + {0x0000a560, 0x49001f0d}, + {0x0000a564, 0x4b001ed2}, + {0x0000a568, 0x4c001ed4}, + {0x0000a56c, 0x4e001f15}, + {0x0000a570, 0x4f001ff6}, + {0x0000a574, 0x4f001ff6}, + {0x0000a578, 0x4f001ff6}, + {0x0000a57c, 0x4f001ff6}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x00804201}, + {0x0000a610, 0x01008201}, + {0x0000a614, 0x0180c402}, + {0x0000a618, 0x0180c603}, + {0x0000a61c, 0x0180c603}, + {0x0000a620, 0x01c10603}, + {0x0000a624, 0x01c10704}, + {0x0000a628, 0x02c18b05}, + {0x0000a62c, 0x02c14c07}, + {0x0000a630, 0x01008704}, + {0x0000a634, 0x01c10402}, + {0x0000a638, 0x0301cc07}, + {0x0000a63c, 0x0301cc07}, + {0x0000b2dc, 0xffd5f552}, + {0x0000b2e0, 0xffe60664}, + {0x0000b2e4, 0xfff80780}, + {0x0000b2e8, 0xfffff800}, + {0x00016044, 0x049242db}, + {0x00016048, 0x6c927a70}, + {0x00016444, 0x049242db}, + {0x00016448, 0x6c927a70}, +}; + +static const u32 qca953x_1p1_modes_xpa_tx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a2dc, 0xfffb52aa}, + {0x0000a2e0, 0xfffd64cc}, + {0x0000a2e4, 0xfffe80f0}, + {0x0000a2e8, 0xffffff00}, + {0x0000a410, 0x000050d5}, + {0x0000a500, 0x00000000}, + {0x0000a504, 0x04000002}, + {0x0000a508, 0x08000004}, + {0x0000a50c, 0x0c000006}, + {0x0000a510, 0x1000000a}, + {0x0000a514, 0x1400000c}, + {0x0000a518, 0x1800000e}, + {0x0000a51c, 0x1c000048}, + {0x0000a520, 0x2000004a}, + {0x0000a524, 0x2400004c}, + {0x0000a528, 0x2800004e}, + {0x0000a52c, 0x2b00024a}, + {0x0000a530, 0x2f00024c}, + {0x0000a534, 0x3300024e}, + {0x0000a538, 0x36000668}, + {0x0000a53c, 0x38000669}, + {0x0000a540, 0x3a000868}, + {0x0000a544, 0x3d00086a}, + {0x0000a548, 0x4000086c}, + {0x0000a54c, 0x4200086e}, + {0x0000a550, 0x43000a6e}, + {0x0000a554, 0x43000a6e}, + {0x0000a558, 0x43000a6e}, + {0x0000a55c, 0x43000a6e}, + {0x0000a560, 0x43000a6e}, + {0x0000a564, 0x43000a6e}, + {0x0000a568, 0x43000a6e}, + {0x0000a56c, 0x43000a6e}, + {0x0000a570, 0x43000a6e}, + {0x0000a574, 0x43000a6e}, + {0x0000a578, 0x43000a6e}, + {0x0000a57c, 0x43000a6e}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x03804000}, + {0x0000a610, 0x03804e01}, + {0x0000a614, 0x03804e01}, + {0x0000a618, 0x03804e01}, + {0x0000a61c, 0x04009002}, + {0x0000a620, 0x04009002}, + {0x0000a624, 0x04009002}, + {0x0000a628, 0x04009002}, + {0x0000a62c, 0x04009002}, + {0x0000a630, 0x04009002}, + {0x0000a634, 0x04009002}, + {0x0000a638, 0x04009002}, + {0x0000a63c, 0x04009002}, + {0x0000b2dc, 0xfffb52aa}, + {0x0000b2e0, 0xfffd64cc}, + {0x0000b2e4, 0xfffe80f0}, + {0x0000b2e8, 0xffffff00}, + {0x00016044, 0x024922db}, + {0x00016048, 0x6c927a70}, + {0x00016444, 0x024922db}, + {0x00016448, 0x6c927a70}, +}; + +static const u32 qca953x_1p1_modes_no_xpa_low_power_tx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a2dc, 0xfff55592}, + {0x0000a2e0, 0xfff99924}, + {0x0000a2e4, 0xfffe1e00}, + {0x0000a2e8, 0xffffe000}, + {0x0000a410, 0x000050d6}, + {0x0000a500, 0x00000069}, + {0x0000a504, 0x0400006b}, + {0x0000a508, 0x0800006d}, + {0x0000a50c, 0x0c000269}, + {0x0000a510, 0x1000026b}, + {0x0000a514, 0x1400026d}, + {0x0000a518, 0x18000669}, + {0x0000a51c, 0x1c00066b}, + {0x0000a520, 0x1d000a68}, + {0x0000a524, 0x21000a6a}, + {0x0000a528, 0x25000a6c}, + {0x0000a52c, 0x29000a6e}, + {0x0000a530, 0x2d0012a9}, + {0x0000a534, 0x310012ab}, + {0x0000a538, 0x350012ad}, + {0x0000a53c, 0x39001b0a}, + {0x0000a540, 0x3d001b0c}, + {0x0000a544, 0x41001b0e}, + {0x0000a548, 0x43001bae}, + {0x0000a54c, 0x45001914}, + {0x0000a550, 0x47001916}, + {0x0000a554, 0x49001b96}, + {0x0000a558, 0x49001b96}, + {0x0000a55c, 0x49001b96}, + {0x0000a560, 0x49001b96}, + {0x0000a564, 0x49001b96}, + {0x0000a568, 0x49001b96}, + {0x0000a56c, 0x49001b96}, + {0x0000a570, 0x49001b96}, + {0x0000a574, 0x49001b96}, + {0x0000a578, 0x49001b96}, + {0x0000a57c, 0x49001b96}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x00000000}, + {0x0000a610, 0x00000000}, + {0x0000a614, 0x00000000}, + {0x0000a618, 0x00804201}, + {0x0000a61c, 0x01408201}, + {0x0000a620, 0x01408502}, + {0x0000a624, 0x01408502}, + {0x0000a628, 0x01408502}, + {0x0000a62c, 0x01408502}, + {0x0000a630, 0x01408502}, + {0x0000a634, 0x01408502}, + {0x0000a638, 0x01408502}, + {0x0000a63c, 0x01408502}, + {0x0000b2dc, 0xfff55592}, + {0x0000b2e0, 0xfff99924}, + {0x0000b2e4, 0xfffe1e00}, + {0x0000b2e8, 0xffffe000}, + {0x00016044, 0x044922db}, + {0x00016048, 0x6c927a70}, + {0x00016444, 0x044922db}, + {0x00016448, 0x6c927a70}, +}; + +static const u32 qca953x_2p0_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a9f6b}, + {0x0000980c, 0x04900000}, + {0x00009814, 0x0280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x6400a190}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14000600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x32840bbe}, + {0x000098bc, 0x00000002}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x9883800a}, + {0x00009d10, 0x018848c6}, + {0x00009d14, 0x00c0040b}, + {0x00009d18, 0x00000000}, + {0x00009e08, 0x0038230c}, + {0x00009e24, 0x990bb515}, + {0x00009e28, 0x0c6f0000}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009fc0, 0x813e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x02993b93}, + {0x0000a20c, 0x00000000}, + {0x0000a220, 0x00000000}, + {0x0000a224, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a248, 0x00000140}, + {0x0000a2a0, 0x00000007}, + {0x0000a2c0, 0x00000007}, + {0x0000a2c8, 0x00000000}, + {0x0000a2d4, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a364, 0x00000000}, + {0x0000a370, 0x00000000}, + {0x0000a390, 0x00000001}, + {0x0000a394, 0x00000444}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, + {0x0000a3a4, 0x000400ff}, + {0x0000a3a8, 0x6a6a6a6a}, + {0x0000a3ac, 0x6a6a6a6a}, + {0x0000a3b0, 0x00c8641a}, + {0x0000a3b4, 0x0000001a}, + {0x0000a3b8, 0x0088642a}, + {0x0000a3bc, 0x000001fa}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000000}, + {0x0000a3f8, 0x0c9bd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce42108}, + {0x0000a418, 0x2d001dce}, + {0x0000a41c, 0x1ce73908}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce738e7}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00100000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x05000080}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a458, 0x00000000}, + {0x0000a644, 0xbfad9d74}, + {0x0000a648, 0x0048060a}, + {0x0000a64c, 0x00003c37}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x09080504}, + {0x0000a678, 0x0d0c0b0a}, + {0x0000a67c, 0x13121110}, + {0x0000a680, 0x31301514}, + {0x0000a684, 0x35343332}, + {0x0000a688, 0x00000036}, + {0x0000a690, 0x08000838}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000000}, + {0x0000a8d0, 0x004b6a8e}, + {0x0000a8d4, 0x00000820}, + {0x0000a8dc, 0x00000000}, + {0x0000a8f0, 0x00000000}, + {0x0000a8f4, 0x00000000}, + {0x0000b2d0, 0x00000080}, + {0x0000b2d4, 0x00000000}, + {0x0000b2ec, 0x00000000}, + {0x0000b2f0, 0x00000000}, + {0x0000b2f4, 0x00000000}, + {0x0000b2f8, 0x00000000}, + {0x0000b408, 0x0e79e5c0}, + {0x0000b40c, 0x00820820}, + {0x0000b420, 0x00000000}, +}; + +static const u32 qca953x_2p0_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, + {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, + {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcf946220, 0xcf946220}, + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f}, + {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, + {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e}, + {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, + {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, + {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18}, + {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, + {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, + {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, +}; + +static const u32 qca953x_2p0_common_wo_xlna_rx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x03820190}, + {0x0000a030, 0x03840383}, + {0x0000a034, 0x03880385}, + {0x0000a038, 0x038a0389}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x29292929}, + {0x0000a084, 0x29292929}, + {0x0000a088, 0x29292929}, + {0x0000a08c, 0x29292929}, + {0x0000a090, 0x22292929}, + {0x0000a094, 0x1d1d2222}, + {0x0000a098, 0x0c111117}, + {0x0000a09c, 0x00030303}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x32323232}, + {0x0000b084, 0x2f2f3232}, + {0x0000b088, 0x23282a2d}, + {0x0000b08c, 0x1c1e2123}, + {0x0000b090, 0x14171919}, + {0x0000b094, 0x0e0e1214}, + {0x0000b098, 0x03050707}, + {0x0000b09c, 0x00030303}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 qca953x_2p0_common_wo_xlna_rx_gain_bounds[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, +}; + +static const u32 qca953x_2p0_modes_xpa_tx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a2dc, 0xfffb52aa}, + {0x0000a2e0, 0xfffd64cc}, + {0x0000a2e4, 0xfffe80f0}, + {0x0000a2e8, 0xffffff00}, + {0x0000a410, 0x000050d5}, + {0x0000a500, 0x00000000}, + {0x0000a504, 0x04000002}, + {0x0000a508, 0x08000004}, + {0x0000a50c, 0x0c000006}, + {0x0000a510, 0x1000000a}, + {0x0000a514, 0x1400000c}, + {0x0000a518, 0x1800000e}, + {0x0000a51c, 0x1c000048}, + {0x0000a520, 0x2000004a}, + {0x0000a524, 0x2400004c}, + {0x0000a528, 0x2800004e}, + {0x0000a52c, 0x2b00024a}, + {0x0000a530, 0x2f00024c}, + {0x0000a534, 0x3300024e}, + {0x0000a538, 0x36000668}, + {0x0000a53c, 0x38000669}, + {0x0000a540, 0x3a000868}, + {0x0000a544, 0x3d00086a}, + {0x0000a548, 0x4000086c}, + {0x0000a54c, 0x4200086e}, + {0x0000a550, 0x43000a6e}, + {0x0000a554, 0x43000a6e}, + {0x0000a558, 0x43000a6e}, + {0x0000a55c, 0x43000a6e}, + {0x0000a560, 0x43000a6e}, + {0x0000a564, 0x43000a6e}, + {0x0000a568, 0x43000a6e}, + {0x0000a56c, 0x43000a6e}, + {0x0000a570, 0x43000a6e}, + {0x0000a574, 0x43000a6e}, + {0x0000a578, 0x43000a6e}, + {0x0000a57c, 0x43000a6e}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x03804000}, + {0x0000a610, 0x03804e01}, + {0x0000a614, 0x03804e01}, + {0x0000a618, 0x03804e01}, + {0x0000a61c, 0x04009002}, + {0x0000a620, 0x04009002}, + {0x0000a624, 0x04009002}, + {0x0000a628, 0x04009002}, + {0x0000a62c, 0x04009002}, + {0x0000a630, 0x04009002}, + {0x0000a634, 0x04009002}, + {0x0000a638, 0x04009002}, + {0x0000a63c, 0x04009002}, + {0x0000b2dc, 0xfffb52aa}, + {0x0000b2e0, 0xfffd64cc}, + {0x0000b2e4, 0xfffe80f0}, + {0x0000b2e8, 0xffffff00}, + {0x00016044, 0x024922db}, + {0x00016048, 0x6c927a70}, + {0x00016444, 0x024922db}, + {0x00016448, 0x6c927a70}, +}; + +static const u32 qca953x_2p0_modes_no_xpa_tx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a2dc, 0xffd5f552}, + {0x0000a2e0, 0xffe60664}, + {0x0000a2e4, 0xfff80780}, + {0x0000a2e8, 0xfffff800}, + {0x0000a410, 0x000050de}, + {0x0000a500, 0x00000061}, + {0x0000a504, 0x04000063}, + {0x0000a508, 0x08000065}, + {0x0000a50c, 0x0c000261}, + {0x0000a510, 0x10000263}, + {0x0000a514, 0x14000265}, + {0x0000a518, 0x18000482}, + {0x0000a51c, 0x1b000484}, + {0x0000a520, 0x1f000486}, + {0x0000a524, 0x240008c2}, + {0x0000a528, 0x28000cc1}, + {0x0000a52c, 0x2d000ce3}, + {0x0000a530, 0x31000ce5}, + {0x0000a534, 0x350010e5}, + {0x0000a538, 0x360012e5}, + {0x0000a53c, 0x380014e5}, + {0x0000a540, 0x3b0018e5}, + {0x0000a544, 0x3d001d04}, + {0x0000a548, 0x3e001d05}, + {0x0000a54c, 0x40001d07}, + {0x0000a550, 0x42001f27}, + {0x0000a554, 0x43001f67}, + {0x0000a558, 0x46001fe7}, + {0x0000a55c, 0x47001f2b}, + {0x0000a560, 0x49001f0d}, + {0x0000a564, 0x4b001ed2}, + {0x0000a568, 0x4c001ed4}, + {0x0000a56c, 0x4e001f15}, + {0x0000a570, 0x4f001ff6}, + {0x0000a574, 0x4f001ff6}, + {0x0000a578, 0x4f001ff6}, + {0x0000a57c, 0x4f001ff6}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x00804201}, + {0x0000a610, 0x01008201}, + {0x0000a614, 0x0180c402}, + {0x0000a618, 0x0180c603}, + {0x0000a61c, 0x0180c603}, + {0x0000a620, 0x01c10603}, + {0x0000a624, 0x01c10704}, + {0x0000a628, 0x02c18b05}, + {0x0000a62c, 0x02c14c07}, + {0x0000a630, 0x01008704}, + {0x0000a634, 0x01c10402}, + {0x0000a638, 0x0301cc07}, + {0x0000a63c, 0x0301cc07}, + {0x0000b2dc, 0xffd5f552}, + {0x0000b2e0, 0xffe60664}, + {0x0000b2e4, 0xfff80780}, + {0x0000b2e8, 0xfffff800}, + {0x00016044, 0x049242db}, + {0x00016048, 0x6c927a70}, + {0x00016444, 0x049242db}, + {0x00016448, 0x6c927a70}, +}; + +#endif /* INITVALS_953X_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h index ccc5b6c99add..67edf344b427 100644 --- a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h @@ -20,6 +20,14 @@ /* AR955X 1.0 */ +#define ar955x_1p0_soc_postamble ar9300_2p2_soc_postamble + +#define ar955x_1p0_common_rx_gain_table ar9300Common_rx_gain_table_2p2 + +#define ar955x_1p0_common_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define ar955x_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 + static const u32 ar955x_1p0_radio_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xd28b3330, 0xd28b3330}, @@ -37,13 +45,6 @@ static const u32 ar955x_1p0_radio_postamble[][5] = { {0x00016940, 0x10804008, 0x10804008, 0x10804008, 0x10804008}, }; -static const u32 ar955x_1p0_baseband_core_txfir_coeff_japan_2484[][2] = { - /* Addr allmodes */ - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x6f7f0301}, - {0x0000a3a0, 0xca9228ee}, -}; - static const u32 ar955x_1p0_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, @@ -62,7 +63,7 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = { {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822}, + {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10820, 0xcfa10820}, {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -82,7 +83,7 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, @@ -473,266 +474,6 @@ static const u32 ar955x_1p0_mac_core[][2] = { {0x000083d0, 0x8c7901ff}, }; -static const u32 ar955x_1p0_common_rx_gain_table[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x01910190}, - {0x0000a030, 0x01930192}, - {0x0000a034, 0x01950194}, - {0x0000a038, 0x038a0196}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x22222229}, - {0x0000a084, 0x1d1d1d1d}, - {0x0000a088, 0x1d1d1d1d}, - {0x0000a08c, 0x1d1d1d1d}, - {0x0000a090, 0x171d1d1d}, - {0x0000a094, 0x11111717}, - {0x0000a098, 0x00030311}, - {0x0000a09c, 0x00000000}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x23232323}, - {0x0000b084, 0x21232323}, - {0x0000b088, 0x19191c1e}, - {0x0000b08c, 0x12141417}, - {0x0000b090, 0x07070e0e}, - {0x0000b094, 0x03030305}, - {0x0000b098, 0x00000003}, - {0x0000b09c, 0x00000000}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - static const u32 ar955x_1p0_baseband_core[][2] = { /* Addr allmodes */ {0x00009800, 0xafe68e30}, @@ -766,7 +507,7 @@ static const u32 ar955x_1p0_baseband_core[][2] = { {0x00009d04, 0x40206c10}, {0x00009d08, 0x009c4060}, {0x00009d0c, 0x9883800a}, - {0x00009d10, 0x01834061}, + {0x00009d10, 0x01884061}, {0x00009d14, 0x00c0040b}, {0x00009d18, 0x00000000}, {0x00009e08, 0x0038230c}, @@ -804,9 +545,9 @@ static const u32 ar955x_1p0_baseband_core[][2] = { {0x0000a370, 0x00000000}, {0x0000a390, 0x00000001}, {0x0000a394, 0x00000444}, - {0x0000a398, 0x1f020503}, - {0x0000a39c, 0x29180c03}, - {0x0000a3a0, 0x9a8b6844}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, {0x0000a3a4, 0x00000000}, {0x0000a3a8, 0xaaaaaaaa}, {0x0000a3ac, 0x3c466478}, @@ -891,266 +632,6 @@ static const u32 ar955x_1p0_baseband_core[][2] = { {0x0000c420, 0x00000000}, }; -static const u32 ar955x_1p0_common_wo_xlna_rx_gain_table[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x32323232}, - {0x0000b084, 0x2f2f3232}, - {0x0000b088, 0x23282a2d}, - {0x0000b08c, 0x1c1e2123}, - {0x0000b090, 0x14171919}, - {0x0000b094, 0x0e0e1214}, - {0x0000b098, 0x03050707}, - {0x0000b09c, 0x00030303}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; - static const u32 ar955x_1p0_soc_preamble[][2] = { /* Addr allmodes */ {0x00007000, 0x00000000}, @@ -1263,11 +744,6 @@ static const u32 ar955x_1p0_modes_no_xpa_tx_gain_table[][9] = { {0x00016848, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401}, }; -static const u32 ar955x_1p0_soc_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, -}; - static const u32 ar955x_1p0_modes_fast_clock[][3] = { /* Addr 5G_HT20 5G_HT40 */ {0x00001030, 0x00000268, 0x000004d0}, diff --git a/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h index e85a8b076c22..35c1bbb2fa8a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h @@ -20,6 +20,12 @@ /* AR9565 1.0 */ +#define ar9565_1p0_mac_postamble ar9331_1p1_mac_postamble + +#define ar9565_1p0_Modes_lowest_ob_db_tx_gain_table ar9565_1p0_modes_low_ob_db_tx_gain_table + +#define ar9565_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 + static const u32 ar9565_1p0_mac_core[][2] = { /* Addr allmodes */ {0x00000008, 0x00000000}, @@ -182,18 +188,6 @@ static const u32 ar9565_1p0_mac_core[][2] = { {0x000083d0, 0x800301ff}, }; -static const u32 ar9565_1p0_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; - static const u32 ar9565_1p0_baseband_core[][2] = { /* Addr allmodes */ {0x00009800, 0xafe68e30}, @@ -272,9 +266,9 @@ static const u32 ar9565_1p0_baseband_core[][2] = { {0x0000a398, 0x001f0e0f}, {0x0000a39c, 0x0075393f}, {0x0000a3a0, 0xb79f6427}, - {0x0000a3a4, 0x00000000}, - {0x0000a3a8, 0xaaaaaaaa}, - {0x0000a3ac, 0x3c466478}, + {0x0000a3a4, 0x00000011}, + {0x0000a3a8, 0xaaaaaa6e}, + {0x0000a3ac, 0x3c466455}, {0x0000a3c0, 0x20202020}, {0x0000a3c4, 0x22222220}, {0x0000a3c8, 0x20200020}, @@ -295,11 +289,11 @@ static const u32 ar9565_1p0_baseband_core[][2] = { {0x0000a404, 0x00000000}, {0x0000a408, 0x0e79e5c6}, {0x0000a40c, 0x00820820}, - {0x0000a414, 0x1ce739ce}, + {0x0000a414, 0x1ce739c5}, {0x0000a418, 0x2d001dce}, - {0x0000a41c, 0x1ce739ce}, + {0x0000a41c, 0x1ce739c5}, {0x0000a420, 0x000001ce}, - {0x0000a424, 0x1ce739ce}, + {0x0000a424, 0x1ce739c5}, {0x0000a428, 0x000001ce}, {0x0000a42c, 0x1ce739ce}, {0x0000a430, 0x1ce739ce}, @@ -351,9 +345,9 @@ static const u32 ar9565_1p0_baseband_postamble[][5] = { {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, - {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003a4, 0x000003a4}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946222, 0xcf946222}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946220, 0xcf946220}, {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -452,6 +446,7 @@ static const u32 ar9565_1p0_Common_rx_gain_table[][2] = { /* Addr allmodes */ {0x00004050, 0x00300300}, {0x0000406c, 0x00100000}, + {0x00009e20, 0x000003b6}, {0x0000a000, 0x00010000}, {0x0000a004, 0x00030002}, {0x0000a008, 0x00050004}, @@ -710,66 +705,6 @@ static const u32 ar9565_1p0_Common_rx_gain_table[][2] = { {0x0000b1fc, 0x00000196}, }; -static const u32 ar9565_1p0_Modes_lowest_ob_db_tx_gain_table[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0xfc0a9380, 0xfc0a9380, 0xfdab5b52, 0xfdab5b52}, - {0x0000a2e0, 0xffecec00, 0xffecec00, 0xfd339c84, 0xfd339c84}, - {0x0000a2e4, 0xfc0f0000, 0xfc0f0000, 0xfec3e000, 0xfec3e000}, - {0x0000a2e8, 0xfc100000, 0xfc100000, 0xfffc0000, 0xfffc0000}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, - {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, - {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, - {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, - {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, - {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, - {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, - {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, - {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, - {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, - {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, - {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, - {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, - {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, - {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a618, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a61c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a620, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a624, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a628, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a62c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a630, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a634, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a638, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a63c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00016044, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, - {0x00016048, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00016054, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, -}; - static const u32 ar9565_1p0_pciephy_clkreq_disable_L1[][2] = { /* Addr allmodes */ {0x00018c00, 0x18212ede}, diff --git a/drivers/net/wireless/ath/ath9k/ar9565_1p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9565_1p1_initvals.h new file mode 100644 index 000000000000..56810539971e --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9565_1p1_initvals.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INITVALS_9565_1P1_H +#define INITVALS_9565_1P1_H + +/* AR9565 1.1 */ + +#define ar9565_1p1_mac_core ar9565_1p0_mac_core + +#define ar9565_1p1_mac_postamble ar9565_1p0_mac_postamble + +#define ar9565_1p1_baseband_core ar9565_1p0_baseband_core + +#define ar9565_1p1_baseband_postamble ar9565_1p0_baseband_postamble + +#define ar9565_1p1_radio_core ar9565_1p0_radio_core + +#define ar9565_1p1_soc_preamble ar9565_1p0_soc_preamble + +#define ar9565_1p1_soc_postamble ar9565_1p0_soc_postamble + +#define ar9565_1p1_Common_rx_gain_table ar9565_1p0_Common_rx_gain_table + +#define ar9565_1p1_Modes_lowest_ob_db_tx_gain_table ar9565_1p0_Modes_lowest_ob_db_tx_gain_table + +#define ar9565_1p1_pciephy_clkreq_disable_L1 ar9565_1p0_pciephy_clkreq_disable_L1 + +#define ar9565_1p1_modes_fast_clock ar9565_1p0_modes_fast_clock + +#define ar9565_1p1_common_wo_xlna_rx_gain_table ar9565_1p0_common_wo_xlna_rx_gain_table + +#define ar9565_1p1_modes_low_ob_db_tx_gain_table ar9565_1p0_modes_low_ob_db_tx_gain_table + +#define ar9565_1p1_modes_high_ob_db_tx_gain_table ar9565_1p0_modes_high_ob_db_tx_gain_table + +#define ar9565_1p1_modes_high_power_tx_gain_table ar9565_1p0_modes_high_power_tx_gain_table + +#define ar9565_1p1_baseband_core_txfir_coeff_japan_2484 ar9565_1p0_baseband_core_txfir_coeff_japan_2484 + +static const u32 ar9565_1p1_radio_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524}, + {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808}, + {0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70}, + {0x0001610c, 0x40000000, 0x40000000, 0x40000000, 0x40000000}, + {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, +}; + +#endif /* INITVALS_9565_1P1_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar956x_initvals.h b/drivers/net/wireless/ath/ath9k/ar956x_initvals.h new file mode 100644 index 000000000000..db051071c676 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar956x_initvals.h @@ -0,0 +1,1046 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INITVALS_956X_H +#define INITVALS_956X_H + +#define qca956x_1p0_mac_core ar955x_1p0_mac_core + +#define qca956x_1p0_mac_postamble ar9331_1p1_mac_postamble + +#define qca956x_1p0_soc_preamble ar955x_1p0_soc_preamble + +#define qca956x_1p0_soc_postamble ar9300_2p2_soc_postamble + +#define qca956x_1p0_common_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define qca956x_1p0_baseband_postamble_dfs_channel ar9300_2p2_baseband_postamble_dfs_channel + +#define qca956x_1p0_common_wo_xlna_rx_gain_bounds ar955x_1p0_common_wo_xlna_rx_gain_bounds + +#define qca956x_1p0_common_rx_gain_bounds ar955x_1p0_common_rx_gain_bounds + +#define qca956x_1p0_modes_fast_clock ar9462_2p0_modes_fast_clock + +static const u32 qca956x_1p0_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a9f6b}, + {0x0000980c, 0x04900000}, + {0x00009814, 0x0280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x6400a190}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14000600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x32840cbf}, + {0x000098bc, 0x00000002}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x9883800a}, + {0x00009d10, 0x01834061}, + {0x00009d14, 0x00c0040b}, + {0x00009d18, 0x00000000}, + {0x00009e08, 0x0038230c}, + {0x00009e24, 0x990bb514}, + {0x00009e28, 0x0c6f0000}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009fc0, 0x813e4789}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x02993b93}, + {0x0000a20c, 0x00000000}, + {0x0000a218, 0x00000000}, + {0x0000a21c, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a248, 0x00000140}, + {0x0000a2a0, 0x00000007}, + {0x0000a2c0, 0x00000007}, + {0x0000a2c8, 0x00000000}, + {0x0000a2d4, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a360, 0x00000000}, + {0x0000a36c, 0x00000000}, + {0x0000a384, 0x00000001}, + {0x0000a388, 0x00000444}, + {0x0000a38c, 0x00000000}, + {0x0000a390, 0x210d0401}, + {0x0000a394, 0xab9a7144}, + {0x0000a398, 0x00000201}, + {0x0000a39c, 0x42424848}, + {0x0000a3a0, 0x3c466478}, + {0x0000a3a4, 0x3a363600}, + {0x0000a3a8, 0x0000003a}, + {0x0000a3ac, 0x00000000}, + {0x0000a3b0, 0x009011fe}, + {0x0000a3b4, 0x00000034}, + {0x0000a3b8, 0x00b3ec0a}, + {0x0000a3bc, 0x00000036}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000000}, + {0x0000a3f8, 0x0c9bd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce739ce}, + {0x0000a418, 0x2d0019ce}, + {0x0000a41c, 0x1ce739ce}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce739ce}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00100000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x05000080}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a454, 0x05000000}, + {0x0000a458, 0x00000000}, + {0x0000a644, 0xbfad9fee}, + {0x0000a648, 0x0048660d}, + {0x0000a64c, 0x00003c37}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x21200504}, + {0x0000a678, 0x61602322}, + {0x0000a67c, 0x65646362}, + {0x0000a680, 0x6b6a6968}, + {0x0000a684, 0xe2706d6c}, + {0x0000a688, 0x000000e3}, + {0x0000a690, 0x00000838}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000000}, + {0x0000a8d0, 0x004b6a8e}, + {0x0000a8d4, 0x00000820}, + {0x0000a8dc, 0x00000000}, + {0x0000a8f0, 0x00000000}, + {0x0000a8f4, 0x00000000}, + {0x0000b2d0, 0x00000080}, + {0x0000b2d4, 0x00000000}, + {0x0000b2ec, 0x00000000}, + {0x0000b2f0, 0x00000000}, + {0x0000b2f4, 0x00000000}, + {0x0000b2f8, 0x00000000}, + {0x0000b408, 0x0e79e5c0}, + {0x0000b40c, 0x00820820}, + {0x0000b420, 0x00000000}, + {0x0000b8d0, 0x004b6a8e}, + {0x0000b8d4, 0x00000820}, + {0x0000b8dc, 0x00000000}, + {0x0000b8f0, 0x00000000}, + {0x0000b8f4, 0x00000000}, + {0x0000c2d0, 0x00000080}, + {0x0000c2d4, 0x00000000}, + {0x0000c2ec, 0x00000000}, + {0x0000c2f0, 0x00000000}, + {0x0000c2f4, 0x00000000}, + {0x0000c2f8, 0x00000000}, + {0x0000c408, 0x0e79e5c0}, + {0x0000c40c, 0x00820820}, + {0x0000c420, 0x00000000}, +}; + +static const u32 qca956x_1p0_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac621f1, 0x5ac621f1}, + {0x00009828, 0x06903081, 0x06903081, 0x07d43881, 0x07d43881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, + {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, + {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000de, 0x6c4000de}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x337d605e, 0x337d5d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003a6, 0x000003a6}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcf946220, 0xcf946220}, + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x045c0cc4, 0x045c0cc0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f}, + {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, + {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, + {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e}, + {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, + {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, + {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, + {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, + {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, + {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001a6, 0x000001a6}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, + {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000be04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, + {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000be20, 0x000001b5, 0x000001b5, 0x000001a6, 0x000001a6}, + {0x0000c284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, +}; + +static const u32 qca956x_1p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db6db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016040, 0x3f80fff8}, + {0x0001604c, 0x000f0278}, + {0x00016050, 0x8036db6c}, + {0x00016054, 0x6db60000}, + {0x00016080, 0x00080000}, + {0x00016084, 0x0e48048c}, + {0x00016088, 0x14214514}, + {0x0001608c, 0x119f080a}, + {0x00016090, 0x24926490}, + {0x00016094, 0x00000000}, + {0x000160a0, 0xc2108ffe}, + {0x000160a4, 0x812fc370}, + {0x000160a8, 0x423c8000}, + {0x000160b4, 0x92480000}, + {0x000160c0, 0x006db6d8}, + {0x000160c4, 0x24b6db6c}, + {0x000160c8, 0x6db6db6c}, + {0x000160cc, 0x6db6fb7c}, + {0x000160d0, 0x6db6da44}, + {0x00016100, 0x07ff8001}, + {0x00016108, 0x00080010}, + {0x00016144, 0x01884080}, + {0x00016148, 0x00008058}, + {0x00016288, 0x001c6000}, + {0x0001628c, 0x50000000}, + {0x000162c0, 0x4b962100}, + {0x000162c4, 0x00000480}, + {0x000162c8, 0x04000144}, + {0x00016380, 0x00000000}, + {0x00016384, 0x00000000}, + {0x00016388, 0x00800700}, + {0x0001638c, 0x00800700}, + {0x00016390, 0x00800700}, + {0x00016394, 0x00000000}, + {0x00016398, 0x00000000}, + {0x0001639c, 0x00000000}, + {0x000163a0, 0x00000001}, + {0x000163a4, 0x00000001}, + {0x000163a8, 0x00000000}, + {0x000163ac, 0x00000000}, + {0x000163b0, 0x00000000}, + {0x000163b4, 0x00000000}, + {0x000163b8, 0x00000000}, + {0x000163bc, 0x00000000}, + {0x000163c0, 0x000000a0}, + {0x000163c4, 0x000c0000}, + {0x000163c8, 0x14021402}, + {0x000163cc, 0x00001402}, + {0x000163d0, 0x00000000}, + {0x000163d4, 0x00000000}, + {0x00016400, 0x36db6db6}, + {0x00016404, 0x6db6db40}, + {0x00016408, 0x73f00000}, + {0x0001640c, 0x00000000}, + {0x00016440, 0x3f80fff8}, + {0x0001644c, 0x000f0278}, + {0x00016450, 0x8036db6c}, + {0x00016454, 0x6db60000}, + {0x00016500, 0x07ff8001}, + {0x00016508, 0x00080010}, + {0x00016544, 0x01884080}, + {0x00016548, 0x00008058}, + {0x00016780, 0x00000000}, + {0x00016784, 0x00000000}, + {0x00016788, 0x00800700}, + {0x0001678c, 0x00800700}, + {0x00016790, 0x00800700}, + {0x00016794, 0x00000000}, + {0x00016798, 0x00000000}, + {0x0001679c, 0x00000000}, + {0x000167a0, 0x00000001}, + {0x000167a4, 0x00000001}, + {0x000167a8, 0x00000000}, + {0x000167ac, 0x00000000}, + {0x000167b0, 0x00000000}, + {0x000167b4, 0x00000000}, + {0x000167b8, 0x00000000}, + {0x000167bc, 0x00000000}, + {0x000167c0, 0x000000a0}, + {0x000167c4, 0x000c0000}, + {0x000167c8, 0x14021402}, + {0x000167cc, 0x00001402}, + {0x000167d0, 0x00000000}, + {0x000167d4, 0x00000000}, + {0x00016800, 0x36db6db6}, + {0x00016804, 0x6db6db40}, + {0x00016808, 0x73f00000}, + {0x0001680c, 0x00000000}, + {0x00016840, 0x3f80fff8}, + {0x0001684c, 0x000f0278}, + {0x00016850, 0x8036db6c}, + {0x00016854, 0x6db60000}, + {0x00016900, 0x07ff8001}, + {0x00016908, 0x00080010}, + {0x00016944, 0x01884080}, + {0x00016948, 0x00008058}, + {0x00016b80, 0x00000000}, + {0x00016b84, 0x00000000}, + {0x00016b88, 0x00800700}, + {0x00016b8c, 0x00800700}, + {0x00016b90, 0x00800700}, + {0x00016b94, 0x00000000}, + {0x00016b98, 0x00000000}, + {0x00016b9c, 0x00000000}, + {0x00016ba0, 0x00000001}, + {0x00016ba4, 0x00000001}, + {0x00016ba8, 0x00000000}, + {0x00016bac, 0x00000000}, + {0x00016bb0, 0x00000000}, + {0x00016bb4, 0x00000000}, + {0x00016bb8, 0x00000000}, + {0x00016bbc, 0x00000000}, + {0x00016bc0, 0x000000a0}, + {0x00016bc4, 0x000c0000}, + {0x00016bc8, 0x14021402}, + {0x00016bcc, 0x00001402}, + {0x00016bd0, 0x00000000}, + {0x00016bd4, 0x00000000}, +}; + +static const u32 qca956x_1p0_radio_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xc4128f5c, 0xc4128f5c}, + {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0fd08f25, 0x0fd08f25}, + {0x000160ac, 0xa4647c00, 0xa4647c00, 0x24646800, 0x24646800}, + {0x000160b0, 0x01885f52, 0x01885f52, 0x00fe7f46, 0x00fe7f46}, + {0x00016104, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001}, + {0x0001610c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, + {0x00016140, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, + {0x00016504, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001}, + {0x0001650c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, + {0x00016540, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, + {0x00016904, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001}, + {0x0001690c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, + {0x00016940, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, +}; + +static const u32 qca956x_1p0_baseband_core_txfir_coeff_japan_2484[][2] = { + /* Addr allmodes */ + {0x0000a38c, 0x00000000}, + {0x0000a390, 0x6f7f0301}, + {0x0000a394, 0xca9228ee}, +}; + +static const u32 qca956x_1p0_modes_no_xpa_tx_gain_table[][3] = { + /* Addr 5G 2G */ + {0x0000a2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000a2e0, 0xff323118, 0xff323118}, + {0x0000a2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000a2e8, 0xffc00000, 0xffc00000}, + {0x0000a39c, 0x42424242, 0x42424242}, + {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00}, + {0x0000a3b0, 0x00a01404, 0x00a01404}, + {0x0000a3b4, 0x00000034, 0x00000034}, + {0x0000a3b8, 0x00800408, 0x00800408}, + {0x0000a3bc, 0x00000036, 0x00000036}, + {0x0000a410, 0x000050dc, 0x000050dc}, + {0x0000a500, 0x09000040, 0x09000040}, + {0x0000a504, 0x0b000041, 0x0b000041}, + {0x0000a508, 0x0d000042, 0x0d000042}, + {0x0000a50c, 0x11000044, 0x11000044}, + {0x0000a510, 0x15000046, 0x15000046}, + {0x0000a514, 0x1d000440, 0x1d000440}, + {0x0000a518, 0x1f000441, 0x1f000441}, + {0x0000a51c, 0x23000443, 0x23000443}, + {0x0000a520, 0x25000444, 0x25000444}, + {0x0000a524, 0x280004e0, 0x280004e0}, + {0x0000a528, 0x2c0004e2, 0x2c0004e2}, + {0x0000a52c, 0x2e0004e3, 0x2e0004e3}, + {0x0000a530, 0x300004e4, 0x300004e4}, + {0x0000a534, 0x340004e6, 0x340004e6}, + {0x0000a538, 0x37000ce0, 0x37000ce0}, + {0x0000a53c, 0x3b000ce2, 0x3b000ce2}, + {0x0000a540, 0x3d000ce3, 0x3d000ce3}, + {0x0000a544, 0x3f000ce4, 0x3f000ce4}, + {0x0000a548, 0x45001ee0, 0x45001ee0}, + {0x0000a54c, 0x49001ee2, 0x49001ee2}, + {0x0000a550, 0x4d001ee4, 0x4d001ee4}, + {0x0000a554, 0x51001ee6, 0x51001ee6}, + {0x0000a558, 0x55001eea, 0x55001eea}, + {0x0000a55c, 0x59001eec, 0x59001eec}, + {0x0000a560, 0x5d001ef0, 0x5d001ef0}, + {0x0000a564, 0x5f001ef1, 0x5f001ef1}, + {0x0000a568, 0x60001ef2, 0x60001ef2}, + {0x0000a56c, 0x61001ef3, 0x61001ef3}, + {0x0000a570, 0x62001ef4, 0x62001ef4}, + {0x0000a574, 0x63001ef5, 0x63001ef5}, + {0x0000a578, 0x64001ffc, 0x64001ffc}, + {0x0000a57c, 0x64001ffc, 0x64001ffc}, + {0x0000a600, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000}, + {0x0000a614, 0x00804201, 0x00804201}, + {0x0000a618, 0x00804201, 0x00804201}, + {0x0000a61c, 0x00804201, 0x00804201}, + {0x0000a620, 0x00804201, 0x00804201}, + {0x0000a624, 0x00804201, 0x00804201}, + {0x0000a628, 0x00804201, 0x00804201}, + {0x0000a62c, 0x02808a02, 0x02808a02}, + {0x0000a630, 0x0340cd03, 0x0340cd03}, + {0x0000a634, 0x0340cd03, 0x0340cd03}, + {0x0000a638, 0x0340cd03, 0x0340cd03}, + {0x0000a63c, 0x05011404, 0x05011404}, + {0x0000b2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000b2e0, 0xff323118, 0xff323118}, + {0x0000b2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000b2e8, 0xffc00000, 0xffc00000}, + {0x0000c2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000c2e0, 0xff323118, 0xff323118}, + {0x0000c2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000c2e8, 0xffc00000, 0xffc00000}, + {0x00016044, 0x049242db, 0x049242db}, + {0x00016048, 0x64925a70, 0x64925a70}, + {0x00016148, 0x00008050, 0x00008050}, + {0x00016280, 0x41110005, 0x41110005}, + {0x00016284, 0x453a6000, 0x453a6000}, + {0x00016444, 0x049242db, 0x049242db}, + {0x00016448, 0x6c925a70, 0x6c925a70}, + {0x00016548, 0x00008050, 0x00008050}, + {0x00016844, 0x049242db, 0x049242db}, + {0x00016848, 0x6c925a70, 0x6c925a70}, + {0x00016948, 0x00008050, 0x00008050}, +}; + +static const u32 qca956x_1p0_modes_xpa_tx_gain_table[][3] = { + /* Addr 5G 2G */ + {0x0000a2dc, 0xcc69ac94, 0xcc69ac94}, + {0x0000a2e0, 0xf0b23118, 0xf0b23118}, + {0x0000a2e4, 0xffffc000, 0xffffc000}, + {0x0000a2e8, 0xc0000000, 0xc0000000}, + {0x0000a410, 0x000050d2, 0x000050d2}, + {0x0000a500, 0x0a000040, 0x0a000040}, + {0x0000a504, 0x0c000041, 0x0c000041}, + {0x0000a508, 0x0e000042, 0x0e000042}, + {0x0000a50c, 0x12000044, 0x12000044}, + {0x0000a510, 0x16000046, 0x16000046}, + {0x0000a514, 0x1d000440, 0x1d000440}, + {0x0000a518, 0x1f000441, 0x1f000441}, + {0x0000a51c, 0x23000443, 0x23000443}, + {0x0000a520, 0x25000444, 0x25000444}, + {0x0000a524, 0x29000a40, 0x29000a40}, + {0x0000a528, 0x2d000a42, 0x2d000a42}, + {0x0000a52c, 0x2f000a43, 0x2f000a43}, + {0x0000a530, 0x31000a44, 0x31000a44}, + {0x0000a534, 0x35000a46, 0x35000a46}, + {0x0000a538, 0x38000ce0, 0x38000ce0}, + {0x0000a53c, 0x3c000ce2, 0x3c000ce2}, + {0x0000a540, 0x3e000ce3, 0x3e000ce3}, + {0x0000a544, 0x40000ce4, 0x40000ce4}, + {0x0000a548, 0x46001ee0, 0x46001ee0}, + {0x0000a54c, 0x4a001ee2, 0x4a001ee2}, + {0x0000a550, 0x4e001ee4, 0x4e001ee4}, + {0x0000a554, 0x52001ee6, 0x52001ee6}, + {0x0000a558, 0x56001eea, 0x56001eea}, + {0x0000a55c, 0x5a001eec, 0x5a001eec}, + {0x0000a560, 0x5e001ef0, 0x5e001ef0}, + {0x0000a564, 0x60001ef1, 0x60001ef1}, + {0x0000a568, 0x61001ef2, 0x61001ef2}, + {0x0000a56c, 0x62001ef3, 0x62001ef3}, + {0x0000a570, 0x63001ef4, 0x63001ef4}, + {0x0000a574, 0x64001ef5, 0x64001ef5}, + {0x0000a578, 0x65001ffc, 0x65001ffc}, + {0x0000a57c, 0x65001ffc, 0x65001ffc}, + {0x0000a600, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000}, + {0x0000a614, 0x00000000, 0x00000000}, + {0x0000a618, 0x00000000, 0x00000000}, + {0x0000a61c, 0x00804201, 0x00804201}, + {0x0000a620, 0x00804201, 0x00804201}, + {0x0000a624, 0x00804201, 0x00804201}, + {0x0000a628, 0x00804201, 0x00804201}, + {0x0000a62c, 0x02808a02, 0x02808a02}, + {0x0000a630, 0x0340cd03, 0x0340cd03}, + {0x0000a634, 0x0340cd03, 0x0340cd03}, + {0x0000a638, 0x0340cd03, 0x0340cd03}, + {0x0000a63c, 0x05011404, 0x05011404}, + {0x0000b2dc, 0xcc69ac94, 0xcc69ac94}, + {0x0000b2e0, 0xf0b23118, 0xf0b23118}, + {0x0000b2e4, 0xffffc000, 0xffffc000}, + {0x0000b2e8, 0xc0000000, 0xc0000000}, + {0x0000c2dc, 0xcc69ac94, 0xcc69ac94}, + {0x0000c2e0, 0xf0b23118, 0xf0b23118}, + {0x0000c2e4, 0xffffc000, 0xffffc000}, + {0x0000c2e8, 0xc0000000, 0xc0000000}, + {0x00016044, 0x012492db, 0x012492db}, + {0x00016048, 0x6c927a70, 0x6c927a70}, + {0x00016050, 0x8036d36c, 0x8036d36c}, + {0x00016280, 0x41110005, 0x41110005}, + {0x00016284, 0x453a7e00, 0x453a7e00}, + {0x00016444, 0x012492db, 0x012492db}, + {0x00016448, 0x6c927a70, 0x6c927a70}, + {0x00016450, 0x8036d36c, 0x8036d36c}, + {0x00016844, 0x012492db, 0x012492db}, + {0x00016848, 0x6c927a70, 0x6c927a70}, + {0x00016850, 0x8036d36c, 0x8036d36c}, +}; + +static const u32 qca956x_1p0_modes_no_xpa_low_ob_db_tx_gain_table[][3] = { + /* Addr 5G 2G */ + {0x0000a2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000a2e0, 0xff323118, 0xff323118}, + {0x0000a2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000a2e8, 0xffc00000, 0xffc00000}, + {0x0000a39c, 0x42424242, 0x42424242}, + {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00}, + {0x0000a3b0, 0x00a01404, 0x00a01404}, + {0x0000a3b4, 0x00000034, 0x00000034}, + {0x0000a3b8, 0x00800408, 0x00800408}, + {0x0000a3bc, 0x00000036, 0x00000036}, + {0x0000a410, 0x000050dc, 0x000050dc}, + {0x0000a414, 0x16b739ce, 0x16b739ce}, + {0x0000a418, 0x2d00198b, 0x2d00198b}, + {0x0000a41c, 0x16b5adce, 0x16b5adce}, + {0x0000a420, 0x0000014a, 0x0000014a}, + {0x0000a424, 0x14a525cc, 0x14a525cc}, + {0x0000a428, 0x0000012a, 0x0000012a}, + {0x0000a42c, 0x14a5294a, 0x14a5294a}, + {0x0000a430, 0x1294a929, 0x1294a929}, + {0x0000a500, 0x09000040, 0x09000040}, + {0x0000a504, 0x0b000041, 0x0b000041}, + {0x0000a508, 0x0d000042, 0x0d000042}, + {0x0000a50c, 0x11000044, 0x11000044}, + {0x0000a510, 0x15000046, 0x15000046}, + {0x0000a514, 0x1d000440, 0x1d000440}, + {0x0000a518, 0x1f000441, 0x1f000441}, + {0x0000a51c, 0x23000443, 0x23000443}, + {0x0000a520, 0x25000444, 0x25000444}, + {0x0000a524, 0x280004e0, 0x280004e0}, + {0x0000a528, 0x2c0004e2, 0x2c0004e2}, + {0x0000a52c, 0x2e0004e3, 0x2e0004e3}, + {0x0000a530, 0x300004e4, 0x300004e4}, + {0x0000a534, 0x340004e6, 0x340004e6}, + {0x0000a538, 0x37000ce0, 0x37000ce0}, + {0x0000a53c, 0x3b000ce2, 0x3b000ce2}, + {0x0000a540, 0x3d000ce3, 0x3d000ce3}, + {0x0000a544, 0x3f000ce4, 0x3f000ce4}, + {0x0000a548, 0x45001ee0, 0x45001ee0}, + {0x0000a54c, 0x49001ee2, 0x49001ee2}, + {0x0000a550, 0x4d001ee4, 0x4d001ee4}, + {0x0000a554, 0x51001ee6, 0x51001ee6}, + {0x0000a558, 0x55001eea, 0x55001eea}, + {0x0000a55c, 0x59001eec, 0x59001eec}, + {0x0000a560, 0x5d001ef0, 0x5d001ef0}, + {0x0000a564, 0x5f001ef1, 0x5f001ef1}, + {0x0000a568, 0x60001ef2, 0x60001ef2}, + {0x0000a56c, 0x61001ef3, 0x61001ef3}, + {0x0000a570, 0x62001ef4, 0x62001ef4}, + {0x0000a574, 0x63001ef5, 0x63001ef5}, + {0x0000a578, 0x64001ffc, 0x64001ffc}, + {0x0000a57c, 0x64001ffc, 0x64001ffc}, + {0x0000a600, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000}, + {0x0000a614, 0x00804201, 0x00804201}, + {0x0000a618, 0x00804201, 0x00804201}, + {0x0000a61c, 0x00804201, 0x00804201}, + {0x0000a620, 0x00804201, 0x00804201}, + {0x0000a624, 0x00804201, 0x00804201}, + {0x0000a628, 0x00804201, 0x00804201}, + {0x0000a62c, 0x02808a02, 0x02808a02}, + {0x0000a630, 0x0340cd03, 0x0340cd03}, + {0x0000a634, 0x0340cd03, 0x0340cd03}, + {0x0000a638, 0x0340cd03, 0x0340cd03}, + {0x0000a63c, 0x05011404, 0x05011404}, + {0x0000b2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000b2e0, 0xff323118, 0xff323118}, + {0x0000b2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000b2e8, 0xffc00000, 0xffc00000}, + {0x0000c2dc, 0xffa9ac94, 0xffa9ac94}, + {0x0000c2e0, 0xff323118, 0xff323118}, + {0x0000c2e4, 0xff3ffe00, 0xff3ffe00}, + {0x0000c2e8, 0xffc00000, 0xffc00000}, + {0x00016044, 0x046e42db, 0x046e42db}, + {0x00016048, 0x64925a70, 0x64925a70}, + {0x00016148, 0x00008050, 0x00008050}, + {0x00016280, 0x41110005, 0x41110005}, + {0x00016284, 0x453a6000, 0x453a6000}, + {0x00016444, 0x046e42db, 0x046e42db}, + {0x00016448, 0x6c925a70, 0x6c925a70}, + {0x00016548, 0x00008050, 0x00008050}, + {0x00016844, 0x046e42db, 0x046e42db}, + {0x00016848, 0x6c925a70, 0x6c925a70}, + {0x00016948, 0x00008050, 0x00008050}, +}; + +static const u32 qca956x_1p0_modes_no_xpa_green_tx_gain_table[][3] = { + /* Addr 5G 2G */ + {0x000098bc, 0x00000001, 0x00000001}, + {0x0000a2dc, 0xd3555284, 0xd3555284}, + {0x0000a2e0, 0x1c666318, 0x1c666318}, + {0x0000a2e4, 0xe07bbc00, 0xe07bbc00}, + {0x0000a2e8, 0xff800000, 0xff800000}, + {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00}, + {0x0000a410, 0x000050dc, 0x000050dc}, + {0x0000a500, 0x02000040, 0x02000040}, + {0x0000a504, 0x04000041, 0x04000041}, + {0x0000a508, 0x06000042, 0x06000042}, + {0x0000a50c, 0x0a000044, 0x0a000044}, + {0x0000a510, 0x0c000045, 0x0c000045}, + {0x0000a514, 0x13000440, 0x13000440}, + {0x0000a518, 0x15000441, 0x15000441}, + {0x0000a51c, 0x19000443, 0x19000443}, + {0x0000a520, 0x1b000444, 0x1b000444}, + {0x0000a524, 0x1e0004e0, 0x1e0004e0}, + {0x0000a528, 0x220004e2, 0x220004e2}, + {0x0000a52c, 0x240004e3, 0x240004e3}, + {0x0000a530, 0x260004e4, 0x260004e4}, + {0x0000a534, 0x2a0004e6, 0x2a0004e6}, + {0x0000a538, 0x32000ce0, 0x32000ce0}, + {0x0000a53c, 0x36000ce2, 0x36000ce2}, + {0x0000a540, 0x3a000ce4, 0x3a000ce4}, + {0x0000a544, 0x3e000ce6, 0x3e000ce6}, + {0x0000a548, 0x45001ee0, 0x45001ee0}, + {0x0000a54c, 0x49001ee2, 0x49001ee2}, + {0x0000a550, 0x4d001ee4, 0x4d001ee4}, + {0x0000a554, 0x51001ee6, 0x51001ee6}, + {0x0000a558, 0x55001eea, 0x55001eea}, + {0x0000a55c, 0x59001eec, 0x59001eec}, + {0x0000a560, 0x5d001ef0, 0x5d001ef0}, + {0x0000a564, 0x5f001ef1, 0x5f001ef1}, + {0x0000a568, 0x60001ef2, 0x60001ef2}, + {0x0000a56c, 0x61001ef3, 0x61001ef3}, + {0x0000a570, 0x62001ef4, 0x62001ef4}, + {0x0000a574, 0x63001ff5, 0x63001ff5}, + {0x0000a578, 0x64001ffc, 0x64001ffc}, + {0x0000a57c, 0x64001ffc, 0x64001ffc}, + {0x0000a600, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000}, + {0x0000a614, 0x00804201, 0x00804201}, + {0x0000a618, 0x00804201, 0x00804201}, + {0x0000a61c, 0x00804201, 0x00804201}, + {0x0000a620, 0x00804201, 0x00804201}, + {0x0000a624, 0x00804201, 0x00804201}, + {0x0000a628, 0x00804201, 0x00804201}, + {0x0000a62c, 0x02808a02, 0x02808a02}, + {0x0000a630, 0x0340cd03, 0x0340cd03}, + {0x0000a634, 0x0340cd03, 0x0340cd03}, + {0x0000a638, 0x0340cd03, 0x0340cd03}, + {0x0000a63c, 0x05011404, 0x05011404}, + {0x0000b2dc, 0xd3555284, 0xd3555284}, + {0x0000b2e0, 0x1c666318, 0x1c666318}, + {0x0000b2e4, 0xe07bbc00, 0xe07bbc00}, + {0x0000b2e8, 0xff800000, 0xff800000}, + {0x0000c2dc, 0xd3555284, 0xd3555284}, + {0x0000c2e0, 0x1c666318, 0x1c666318}, + {0x0000c2e4, 0xe07bbc00, 0xe07bbc00}, + {0x0000c2e8, 0xff800000, 0xff800000}, + {0x00016044, 0x849242db, 0x849242db}, + {0x00016048, 0x64925a70, 0x64925a70}, + {0x00016280, 0x41110005, 0x41110005}, + {0x00016284, 0x453a6000, 0x453a6000}, + {0x00016444, 0x849242db, 0x849242db}, + {0x00016448, 0x6c925a70, 0x6c925a70}, + {0x00016844, 0x849242db, 0x849242db}, + {0x00016848, 0x6c925a70, 0x6c925a70}, + {0x0000a7f0, 0x800002cc, 0x800002cc}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000018, 0x00000018}, + {0x0000a7f4, 0x00000028, 0x00000028}, + {0x0000a7f4, 0x00000028, 0x00000028}, + {0x0000a7f4, 0x00000028, 0x00000028}, + {0x0000a7f4, 0x00000028, 0x00000028}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, + {0x0000a7f4, 0x00000048, 0x00000048}, +}; + +static const u32 qca956x_1p0_common_rx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x01910190}, + {0x0000a030, 0x01930192}, + {0x0000a034, 0x01950194}, + {0x0000a038, 0x038a0196}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x22222222}, + {0x0000a084, 0x1d1d1d1d}, + {0x0000a088, 0x1d1d1d1d}, + {0x0000a08c, 0x1d1d1d1d}, + {0x0000a090, 0x17171717}, + {0x0000a094, 0x11111717}, + {0x0000a098, 0x00030311}, + {0x0000a09c, 0x00000000}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x23232323}, + {0x0000b084, 0x21232323}, + {0x0000b088, 0x19191c1e}, + {0x0000b08c, 0x12141417}, + {0x0000b090, 0x07070e0e}, + {0x0000b094, 0x03030305}, + {0x0000b098, 0x00000003}, + {0x0000b09c, 0x00000000}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 qca956x_1p0_xlna_only[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac621f1, 0x5ac621f1}, + {0x00009828, 0x06903081, 0x06903081, 0x07d43881, 0x07d43881}, + {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x03721720}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000de, 0x6c4000da}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec86d2e, 0x7ec8ad2e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x317a6062, 0x317a5ae2}, + {0x00009e18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003b2, 0x000003b2}, + {0x00009fc0, 0x813e4788, 0x813e4788, 0x813e4789, 0x813e4789}, + {0x0000ae18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001b2, 0x000001b2}, + {0x0000be18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000}, + {0x0000be20, 0x000001b5, 0x000001b5, 0x000001b2, 0x000001b2}, +}; + +#endif /* INITVALS_956X_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h index bdee2ed67219..fab14e0a87b9 100644 --- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h @@ -20,18 +20,176 @@ /* AR9580 1.0 */ +#define ar9580_1p0_soc_preamble ar9300_2p2_soc_preamble + +#define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble + +static const u32 ar9580_1p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db2db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016040, 0x7f80fff8}, + {0x0001604c, 0x76d005b5}, + {0x00016050, 0x556cf031}, + {0x00016054, 0x13449440}, + {0x00016058, 0x0c51c92c}, + {0x0001605c, 0x3db7fffc}, + {0x00016060, 0xfffffffc}, + {0x00016064, 0x000f0278}, + {0x0001606c, 0x6db60000}, + {0x00016080, 0x00000000}, + {0x00016084, 0x0e48048c}, + {0x00016088, 0x54214514}, + {0x0001608c, 0x119f481e}, + {0x00016090, 0x24926490}, + {0x00016098, 0xd2888888}, + {0x000160a0, 0x0a108ffe}, + {0x000160a4, 0x812fc370}, + {0x000160a8, 0x423c8000}, + {0x000160b4, 0x92480080}, + {0x000160c0, 0x00adb6d0}, + {0x000160c4, 0x6db6db60}, + {0x000160c8, 0x6db6db6c}, + {0x000160cc, 0x01e6c000}, + {0x00016100, 0x3fffbe01}, + {0x00016104, 0xfff80000}, + {0x00016108, 0x00080010}, + {0x00016144, 0x02084080}, + {0x00016148, 0x00000000}, + {0x00016280, 0x058a0001}, + {0x00016284, 0x3d840208}, + {0x00016288, 0x05a20408}, + {0x0001628c, 0x00038c07}, + {0x00016290, 0x00000004}, + {0x00016294, 0x458a214f}, + {0x00016380, 0x00000000}, + {0x00016384, 0x00000000}, + {0x00016388, 0x00800700}, + {0x0001638c, 0x00800700}, + {0x00016390, 0x00800700}, + {0x00016394, 0x00000000}, + {0x00016398, 0x00000000}, + {0x0001639c, 0x00000000}, + {0x000163a0, 0x00000001}, + {0x000163a4, 0x00000001}, + {0x000163a8, 0x00000000}, + {0x000163ac, 0x00000000}, + {0x000163b0, 0x00000000}, + {0x000163b4, 0x00000000}, + {0x000163b8, 0x00000000}, + {0x000163bc, 0x00000000}, + {0x000163c0, 0x000000a0}, + {0x000163c4, 0x000c0000}, + {0x000163c8, 0x14021402}, + {0x000163cc, 0x00001402}, + {0x000163d0, 0x00000000}, + {0x000163d4, 0x00000000}, + {0x00016400, 0x36db2db6}, + {0x00016404, 0x6db6db40}, + {0x00016408, 0x73f00000}, + {0x0001640c, 0x00000000}, + {0x00016440, 0x7f80fff8}, + {0x0001644c, 0x76d005b5}, + {0x00016450, 0x556cf031}, + {0x00016454, 0x13449440}, + {0x00016458, 0x0c51c92c}, + {0x0001645c, 0x3db7fffc}, + {0x00016460, 0xfffffffc}, + {0x00016464, 0x000f0278}, + {0x0001646c, 0x6db60000}, + {0x00016500, 0x3fffbe01}, + {0x00016504, 0xfff80000}, + {0x00016508, 0x00080010}, + {0x00016544, 0x02084080}, + {0x00016548, 0x00000000}, + {0x00016780, 0x00000000}, + {0x00016784, 0x00000000}, + {0x00016788, 0x00800700}, + {0x0001678c, 0x00800700}, + {0x00016790, 0x00800700}, + {0x00016794, 0x00000000}, + {0x00016798, 0x00000000}, + {0x0001679c, 0x00000000}, + {0x000167a0, 0x00000001}, + {0x000167a4, 0x00000001}, + {0x000167a8, 0x00000000}, + {0x000167ac, 0x00000000}, + {0x000167b0, 0x00000000}, + {0x000167b4, 0x00000000}, + {0x000167b8, 0x00000000}, + {0x000167bc, 0x00000000}, + {0x000167c0, 0x000000a0}, + {0x000167c4, 0x000c0000}, + {0x000167c8, 0x14021402}, + {0x000167cc, 0x00001402}, + {0x000167d0, 0x00000000}, + {0x000167d4, 0x00000000}, + {0x00016800, 0x36db2db6}, + {0x00016804, 0x6db6db40}, + {0x00016808, 0x73f00000}, + {0x0001680c, 0x00000000}, + {0x00016840, 0x7f80fff8}, + {0x0001684c, 0x76d005b5}, + {0x00016850, 0x556cf031}, + {0x00016854, 0x13449440}, + {0x00016858, 0x0c51c92c}, + {0x0001685c, 0x3db7fffc}, + {0x00016860, 0xfffffffc}, + {0x00016864, 0x000f0278}, + {0x0001686c, 0x6db60000}, + {0x00016900, 0x3fffbe01}, + {0x00016904, 0xfff80000}, + {0x00016908, 0x00080010}, + {0x00016944, 0x02084080}, + {0x00016948, 0x00000000}, + {0x00016b80, 0x00000000}, + {0x00016b84, 0x00000000}, + {0x00016b88, 0x00800700}, + {0x00016b8c, 0x00800700}, + {0x00016b90, 0x00800700}, + {0x00016b94, 0x00000000}, + {0x00016b98, 0x00000000}, + {0x00016b9c, 0x00000000}, + {0x00016ba0, 0x00000001}, + {0x00016ba4, 0x00000001}, + {0x00016ba8, 0x00000000}, + {0x00016bac, 0x00000000}, + {0x00016bb0, 0x00000000}, + {0x00016bb4, 0x00000000}, + {0x00016bb8, 0x00000000}, + {0x00016bbc, 0x00000000}, + {0x00016bc0, 0x000000a0}, + {0x00016bc4, 0x000c0000}, + {0x00016bc8, 0x14021402}, + {0x00016bcc, 0x00001402}, + {0x00016bd0, 0x00000000}, + {0x00016bd4, 0x00000000}, +}; + +#define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble + +#define ar9580_1p0_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2 + +#define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2 + #define ar9580_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2 +#define ar9580_1p0_baseband_core_txfir_coeff_japan_2484 ar9300_2p2_baseband_core_txfir_coeff_japan_2484 + static const u32 ar9580_1p0_radio_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31}, {0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800}, {0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20}, - {0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0001610c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000}, {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, - {0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0001650c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000}, {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, - {0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0001690c, 0xc8000000, 0xc0000000, 0xc0000000, 0xc0000000}, {0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, }; @@ -41,12 +199,10 @@ static const u32 ar9580_1p0_baseband_core[][2] = { {0x00009804, 0xfd14e000}, {0x00009808, 0x9c0a9f6b}, {0x0000980c, 0x04900000}, - {0x00009814, 0x3280c00a}, - {0x00009818, 0x00000000}, {0x0000981c, 0x00020028}, - {0x00009834, 0x6400a290}, + {0x00009834, 0x6400a190}, {0x00009838, 0x0108ecff}, - {0x0000983c, 0x0d000600}, + {0x0000983c, 0x14000600}, {0x00009880, 0x201fff00}, {0x00009884, 0x00001042}, {0x000098a4, 0x00200400}, @@ -67,7 +223,7 @@ static const u32 ar9580_1p0_baseband_core[][2] = { {0x00009d04, 0x40206c10}, {0x00009d08, 0x009c4060}, {0x00009d0c, 0x9883800a}, - {0x00009d10, 0x01834061}, + {0x00009d10, 0x01884061}, {0x00009d14, 0x00c0040b}, {0x00009d18, 0x00000000}, {0x00009e08, 0x0038230c}, @@ -76,7 +232,7 @@ static const u32 ar9580_1p0_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, + {0x00009e40, 0x0d261800}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, {0x00009e54, 0x00000000}, @@ -198,8 +354,6 @@ static const u32 ar9580_1p0_baseband_core[][2] = { {0x0000c420, 0x00000000}, }; -#define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble - static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, @@ -306,7 +460,112 @@ static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = { {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; -#define ar9580_1p0_high_power_tx_gain_table ar9580_1p0_low_ob_db_tx_gain_table +static const u32 ar9580_1p0_high_power_tx_gain_table[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400}, + {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402}, + {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404}, + {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640}, + {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5e08442e, 0x5e08442e, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x620a4431, 0x620a4431, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x15800028, 0x15800028, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1b80002b, 0x1b80002b, 0x12800400, 0x12800400}, + {0x0000a598, 0x1f820028, 0x1f820028, 0x16800402, 0x16800402}, + {0x0000a59c, 0x2582002b, 0x2582002b, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2a84002a, 0x2a84002a, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2e86002a, 0x2e86002a, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x3382202d, 0x3382202d, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3884202c, 0x3884202c, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3c86202c, 0x3c86202c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4188202d, 0x4188202d, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4586402d, 0x4586402d, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4986222d, 0x4986222d, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4d862231, 0x4d862231, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x50882231, 0x50882231, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5688422e, 0x5688422e, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5a88442e, 0x5a88442e, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x5e8a4431, 0x5e8a4431, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x648a4432, 0x648a4432, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x688a4434, 0x688a4434, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x6c8a6434, 0x6c8a6434, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x6f8a6633, 0x6f8a6633, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000}, + {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000}, + {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501}, + {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501}, + {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016048, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016288, 0x05a2040a, 0x05a2040a, 0x05a20408, 0x05a20408}, + {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016448, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016848, 0x65240001, 0x65240001, 0x66480001, 0x66480001}, + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +}; static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ @@ -414,8 +673,6 @@ static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = { {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; -#define ar9580_1p0_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 - static const u32 ar9580_1p0_mac_core[][2] = { /* Addr allmodes */ {0x00000008, 0x00000000}, @@ -679,14 +936,6 @@ static const u32 ar9580_1p0_mixed_ob_db_tx_gain_table[][5] = { {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; -#define ar9580_1p0_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 - -#define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble - -#define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2 - -#define ar9580_1p0_type5_tx_gain_table ar9300Modes_type5_tx_gain_table_2p2 - static const u32 ar9580_1p0_type6_tx_gain_table[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352}, @@ -761,165 +1010,271 @@ static const u32 ar9580_1p0_type6_tx_gain_table[][5] = { {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; -static const u32 ar9580_1p0_soc_preamble[][2] = { - /* Addr allmodes */ - {0x000040a4, 0x00a0c1c9}, - {0x00007008, 0x00000000}, - {0x00007020, 0x00000000}, - {0x00007034, 0x00000002}, - {0x00007038, 0x000004c2}, - {0x00007048, 0x00000008}, -}; - -#define ar9580_1p0_rx_gain_table ar9462_common_rx_gain_table_2p0 - -static const u32 ar9580_1p0_radio_core[][2] = { +static const u32 ar9580_1p0_rx_gain_table[][2] = { /* Addr allmodes */ - {0x00016000, 0x36db6db6}, - {0x00016004, 0x6db6db40}, - {0x00016008, 0x73f00000}, - {0x0001600c, 0x00000000}, - {0x00016040, 0x7f80fff8}, - {0x0001604c, 0x76d005b5}, - {0x00016050, 0x556cf031}, - {0x00016054, 0x13449440}, - {0x00016058, 0x0c51c92c}, - {0x0001605c, 0x3db7fffc}, - {0x00016060, 0xfffffffc}, - {0x00016064, 0x000f0278}, - {0x0001606c, 0x6db60000}, - {0x00016080, 0x00000000}, - {0x00016084, 0x0e48048c}, - {0x00016088, 0x54214514}, - {0x0001608c, 0x119f481e}, - {0x00016090, 0x24926490}, - {0x00016098, 0xd2888888}, - {0x000160a0, 0x0a108ffe}, - {0x000160a4, 0x812fc370}, - {0x000160a8, 0x423c8000}, - {0x000160b4, 0x92480080}, - {0x000160c0, 0x00adb6d0}, - {0x000160c4, 0x6db6db60}, - {0x000160c8, 0x6db6db6c}, - {0x000160cc, 0x01e6c000}, - {0x00016100, 0x3fffbe01}, - {0x00016104, 0xfff80000}, - {0x00016108, 0x00080010}, - {0x00016144, 0x02084080}, - {0x00016148, 0x00000000}, - {0x00016280, 0x058a0001}, - {0x00016284, 0x3d840208}, - {0x00016288, 0x05a20408}, - {0x0001628c, 0x00038c07}, - {0x00016290, 0x00000004}, - {0x00016294, 0x458aa14f}, - {0x00016380, 0x00000000}, - {0x00016384, 0x00000000}, - {0x00016388, 0x00800700}, - {0x0001638c, 0x00800700}, - {0x00016390, 0x00800700}, - {0x00016394, 0x00000000}, - {0x00016398, 0x00000000}, - {0x0001639c, 0x00000000}, - {0x000163a0, 0x00000001}, - {0x000163a4, 0x00000001}, - {0x000163a8, 0x00000000}, - {0x000163ac, 0x00000000}, - {0x000163b0, 0x00000000}, - {0x000163b4, 0x00000000}, - {0x000163b8, 0x00000000}, - {0x000163bc, 0x00000000}, - {0x000163c0, 0x000000a0}, - {0x000163c4, 0x000c0000}, - {0x000163c8, 0x14021402}, - {0x000163cc, 0x00001402}, - {0x000163d0, 0x00000000}, - {0x000163d4, 0x00000000}, - {0x00016400, 0x36db6db6}, - {0x00016404, 0x6db6db40}, - {0x00016408, 0x73f00000}, - {0x0001640c, 0x00000000}, - {0x00016440, 0x7f80fff8}, - {0x0001644c, 0x76d005b5}, - {0x00016450, 0x556cf031}, - {0x00016454, 0x13449440}, - {0x00016458, 0x0c51c92c}, - {0x0001645c, 0x3db7fffc}, - {0x00016460, 0xfffffffc}, - {0x00016464, 0x000f0278}, - {0x0001646c, 0x6db60000}, - {0x00016500, 0x3fffbe01}, - {0x00016504, 0xfff80000}, - {0x00016508, 0x00080010}, - {0x00016544, 0x02084080}, - {0x00016548, 0x00000000}, - {0x00016780, 0x00000000}, - {0x00016784, 0x00000000}, - {0x00016788, 0x00800700}, - {0x0001678c, 0x00800700}, - {0x00016790, 0x00800700}, - {0x00016794, 0x00000000}, - {0x00016798, 0x00000000}, - {0x0001679c, 0x00000000}, - {0x000167a0, 0x00000001}, - {0x000167a4, 0x00000001}, - {0x000167a8, 0x00000000}, - {0x000167ac, 0x00000000}, - {0x000167b0, 0x00000000}, - {0x000167b4, 0x00000000}, - {0x000167b8, 0x00000000}, - {0x000167bc, 0x00000000}, - {0x000167c0, 0x000000a0}, - {0x000167c4, 0x000c0000}, - {0x000167c8, 0x14021402}, - {0x000167cc, 0x00001402}, - {0x000167d0, 0x00000000}, - {0x000167d4, 0x00000000}, - {0x00016800, 0x36db6db6}, - {0x00016804, 0x6db6db40}, - {0x00016808, 0x73f00000}, - {0x0001680c, 0x00000000}, - {0x00016840, 0x7f80fff8}, - {0x0001684c, 0x76d005b5}, - {0x00016850, 0x556cf031}, - {0x00016854, 0x13449440}, - {0x00016858, 0x0c51c92c}, - {0x0001685c, 0x3db7fffc}, - {0x00016860, 0xfffffffc}, - {0x00016864, 0x000f0278}, - {0x0001686c, 0x6db60000}, - {0x00016900, 0x3fffbe01}, - {0x00016904, 0xfff80000}, - {0x00016908, 0x00080010}, - {0x00016944, 0x02084080}, - {0x00016948, 0x00000000}, - {0x00016b80, 0x00000000}, - {0x00016b84, 0x00000000}, - {0x00016b88, 0x00800700}, - {0x00016b8c, 0x00800700}, - {0x00016b90, 0x00800700}, - {0x00016b94, 0x00000000}, - {0x00016b98, 0x00000000}, - {0x00016b9c, 0x00000000}, - {0x00016ba0, 0x00000001}, - {0x00016ba4, 0x00000001}, - {0x00016ba8, 0x00000000}, - {0x00016bac, 0x00000000}, - {0x00016bb0, 0x00000000}, - {0x00016bb4, 0x00000000}, - {0x00016bb8, 0x00000000}, - {0x00016bbc, 0x00000000}, - {0x00016bc0, 0x000000a0}, - {0x00016bc4, 0x000c0000}, - {0x00016bc8, 0x14021402}, - {0x00016bcc, 0x00001402}, - {0x00016bd0, 0x00000000}, - {0x00016bd4, 0x00000000}, + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x01910190}, + {0x0000a030, 0x01930192}, + {0x0000a034, 0x01950194}, + {0x0000a038, 0x038a0196}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x22222229}, + {0x0000a084, 0x1d1d1d1d}, + {0x0000a088, 0x1d1d1d1d}, + {0x0000a08c, 0x1d1d1d1d}, + {0x0000a090, 0x171d1d1d}, + {0x0000a094, 0x11111717}, + {0x0000a098, 0x00030311}, + {0x0000a09c, 0x00000000}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x23232323}, + {0x0000b084, 0x21232323}, + {0x0000b088, 0x19191c1e}, + {0x0000b08c, 0x12141417}, + {0x0000b090, 0x07070e0e}, + {0x0000b094, 0x03030305}, + {0x0000b098, 0x00000003}, + {0x0000b09c, 0x00000000}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, }; static const u32 ar9580_1p0_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009814, 0x3280c00a, 0x3280c00a, 0x3280c00a, 0x3280c00a}, + {0x00009818, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, @@ -935,7 +1290,7 @@ static const u32 ar9580_1p0_baseband_postamble[][5] = { {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946220, 0xcf946220}, {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -955,8 +1310,8 @@ static const u32 ar9580_1p0_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, + {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, + {0x0000a2d0, 0x00041983, 0x00041983, 0x00041981, 0x00041982}, {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, @@ -973,25 +1328,13 @@ static const u32 ar9580_1p0_baseband_postamble[][5] = { {0x0000c284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, }; -static const u32 ar9580_1p0_pcie_phy_clkreq_enable_L1[][2] = { - /* Addr allmodes */ - {0x00004040, 0x0835365e}, - {0x00004040, 0x0008003b}, - {0x00004044, 0x00000000}, -}; - -static const u32 ar9580_1p0_pcie_phy_clkreq_disable_L1[][2] = { - /* Addr allmodes */ - {0x00004040, 0x0831365e}, - {0x00004040, 0x0008003b}, - {0x00004044, 0x00000000}, -}; - -static const u32 ar9580_1p0_pcie_phy_pll_on_clkreq[][2] = { - /* Addr allmodes */ - {0x00004040, 0x0831265e}, - {0x00004040, 0x0008003b}, - {0x00004044, 0x00000000}, +static const u32 ar9580_1p0_baseband_postamble_dfs_channel[][3] = { + /* Addr 5G 2G */ + {0x00009814, 0x3400c00f, 0x3400c00f}, + {0x00009824, 0x5ac668d0, 0x5ac668d0}, + {0x00009828, 0x06903080, 0x06903080}, + {0x00009e0c, 0x6d4000e2, 0x6d4000e2}, + {0x00009e14, 0x37b9625e, 0x37b9625e}, }; #endif /* INITVALS_9580_1P0_H */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index c1224b5a257b..6e38aa7351e3 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -20,23 +20,34 @@ #include <linux/etherdevice.h> #include <linux/device.h> #include <linux/interrupt.h> +#include <linux/kstrtox.h> #include <linux/leds.h> #include <linux/completion.h> +#include <linux/time.h> +#include <linux/hw_random.h> -#include "debug.h" #include "common.h" +#include "debug.h" #include "mci.h" #include "dfs.h" -/* - * Header for the ath9k.ko driver core *only* -- hw code nor any other driver - * should rely on this file or its contents. - */ - struct ath_node; +struct ath_vif; -/* Macro to expand scalars to 64-bit objects */ +extern struct ieee80211_ops ath9k_ops; +extern int ath9k_modparam_nohwcrypt; +extern int ath9k_led_blink; +extern bool is_ath9k_unloaded; +extern int ath9k_use_chanctx; +extern int ath9k_use_msi; + +/*************************/ +/* Descriptor Management */ +/*************************/ + +#define ATH_TXSTATUS_RING_SIZE 512 +/* Macro to expand scalars to 64-bit objects */ #define ito64(x) (sizeof(x) == 1) ? \ (((unsigned long long int)(x)) & (0xff)) : \ (sizeof(x) == 2) ? \ @@ -45,61 +56,13 @@ struct ath_node; (((unsigned long long int)(x)) & 0xffffffff) : \ (unsigned long long int)(x)) -/* increment with wrap-around */ -#define INCR(_l, _sz) do { \ - (_l)++; \ - (_l) &= ((_sz) - 1); \ - } while (0) - -/* decrement with wrap-around */ -#define DECR(_l, _sz) do { \ - (_l)--; \ - (_l) &= ((_sz) - 1); \ - } while (0) - -#define TSF_TO_TU(_h,_l) \ - ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) - -#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i)) - -struct ath_config { - u16 txpowlimit; - u8 cabqReadytime; -}; - -/*************************/ -/* Descriptor Management */ -/*************************/ - #define ATH_TXBUF_RESET(_bf) do { \ - (_bf)->bf_stale = false; \ (_bf)->bf_lastbf = NULL; \ (_bf)->bf_next = NULL; \ memset(&((_bf)->bf_state), 0, \ sizeof(struct ath_buf_state)); \ } while (0) -#define ATH_RXBUF_RESET(_bf) do { \ - (_bf)->bf_stale = false; \ - } while (0) - -/** - * enum buffer_type - Buffer type flags - * - * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX) - * @BUF_AGGR: Indicates whether the buffer can be aggregated - * (used in aggregation scheduling) - */ -enum buffer_type { - BUF_AMPDU = BIT(0), - BUF_AGGR = BIT(1), -}; - -#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) -#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) - -#define ATH_TXSTATUS_RING_SIZE 512 - #define DS2PHYS(_dd, _ds) \ ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) #define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) @@ -119,11 +82,19 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, /* RX / TX */ /***********/ +#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i)) + +/* increment with wrap-around */ +#define INCR(_l, _sz) do { \ + (_l)++; \ + (_l) &= ((_sz) - 1); \ + } while (0) + #define ATH_RXBUF 512 #define ATH_TXBUF 512 #define ATH_TXBUF_RESERVE 5 -#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE) #define ATH_TXMAXTRY 13 +#define ATH_MAX_SW_RETRIES 30 #define TID_TO_WME_AC(_tid) \ ((((_tid) == 0) || ((_tid) == 3)) ? IEEE80211_AC_BE : \ @@ -137,7 +108,14 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, #define ATH_AGGR_ENCRYPTDELIM 10 /* minimum h/w qdepth to be sustained to maximize aggregation */ #define ATH_AGGR_MIN_QDEPTH 2 -#define ATH_AMPDU_SUBFRAME_DEFAULT 32 +/* minimum h/w qdepth for non-aggregated traffic */ +#define ATH_NON_AGGR_MIN_QDEPTH 8 +#define ATH_HW_CHECK_POLL_INT 1000 +#define ATH_TXFIFO_DEPTH 8 +#define ATH_TX_ERROR 0x01 + +/* Stop tx traffic 1ms before the GO goes away */ +#define ATH_P2P_PS_STOP_TIME 1000 #define IEEE80211_SEQ_SEQ_SHIFT 4 #define IEEE80211_SEQ_MAX 4096 @@ -168,19 +146,17 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, #define BAW_WITHIN(_start, _bawsz, _seqno) \ ((((_seqno) - (_start)) & 4095) < (_bawsz)) -#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) +#define ATH_AN_2_TID(_an, _tidno) ath_node_to_tid(_an, _tidno) -#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e)) +#define IS_HT_RATE(rate) (rate & 0x80) +#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e)) +#define IS_OFDM_RATE(rate) ((rate >= 0x8) && (rate <= 0xf)) -#define ATH_TX_COMPLETE_POLL_INT 1000 - -enum ATH_AGGR_STATUS { - ATH_AGGR_DONE, - ATH_AGGR_BAW_CLOSED, - ATH_AGGR_LIMITED, +enum { + WLAN_RC_PHY_OFDM, + WLAN_RC_PHY_CCK, }; -#define ATH_TXFIFO_DEPTH 8 struct ath_txq { int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */ u32 axq_qnum; /* ath9k hardware queue number */ @@ -189,9 +165,7 @@ struct ath_txq { spinlock_t axq_lock; u32 axq_depth; u32 axq_ampdu_depth; - bool stopped; bool axq_tx_inprogress; - struct list_head axq_acq; struct list_head txq_fifo[ATH_TXFIFO_DEPTH]; u8 txq_headidx; u8 txq_tailidx; @@ -199,27 +173,47 @@ struct ath_txq { struct sk_buff_head complete_q; }; -struct ath_atx_ac { - struct ath_txq *txq; - int sched; - struct list_head list; - struct list_head tid_q; - bool clear_ps_filter; -}; - struct ath_frame_info { struct ath_buf *bf; - int framelen; - enum ath9k_key_type keytype; + u16 framelen; + s8 txq; u8 keyix; - u8 retries; u8 rtscts_rate; + u8 retries : 6; + u8 dyn_smps : 1; + u8 baw_tracked : 1; + u8 tx_power; + enum ath9k_key_type keytype:2; }; +struct ath_rxbuf { + struct list_head list; + struct sk_buff *bf_mpdu; + void *bf_desc; + dma_addr_t bf_daddr; + dma_addr_t bf_buf_addr; +}; + +/** + * enum buffer_type - Buffer type flags + * + * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX) + * @BUF_AGGR: Indicates whether the buffer can be aggregated + * (used in aggregation scheduling) + */ +enum buffer_type { + BUF_AMPDU = BIT(0), + BUF_AGGR = BIT(1), +}; + +#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) +#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) + struct ath_buf_state { u8 bf_type; u8 bfs_paprd; u8 ndelim; + bool stale; u16 seqno; unsigned long bfs_paprd_timestamp; }; @@ -233,55 +227,57 @@ struct ath_buf { void *bf_desc; /* virtual addr of desc */ dma_addr_t bf_daddr; /* physical addr of desc */ dma_addr_t bf_buf_addr; /* physical addr of data buffer, for DMA */ - bool bf_stale; struct ieee80211_tx_rate rates[4]; struct ath_buf_state bf_state; }; struct ath_atx_tid { struct list_head list; - struct sk_buff_head buf_q; + struct sk_buff_head retry_q; struct ath_node *an; - struct ath_atx_ac *ac; + struct ath_txq *txq; unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)]; - int bar_index; u16 seq_start; u16 seq_next; u16 baw_size; - int tidno; + u8 tidno; int baw_head; /* first un-acked tx buffer */ int baw_tail; /* next unused tx buffer slot */ - bool sched; - bool paused; + + s8 bar_index; bool active; + bool clear_ps_filter; }; +void ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid); + struct ath_node { struct ath_softc *sc; struct ieee80211_sta *sta; /* station struct we're part of */ struct ieee80211_vif *vif; /* interface with which we're associated */ - struct ath_atx_tid tid[IEEE80211_NUM_TIDS]; - struct ath_atx_ac ac[IEEE80211_NUM_ACS]; - int ps_key; u16 maxampdu; u8 mpdudensity; + s8 ps_key; bool sleeping; + bool no_ps_filter; -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) - struct dentry *node_stat; +#ifdef CONFIG_ATH9K_STATION_STATISTICS + struct ath_rx_rate_stats rx_rate_stats; #endif + u8 key_idx[4]; + + int ackto; + struct list_head list; }; struct ath_tx_control { struct ath_txq *txq; - struct ath_node *an; - u8 paprd; struct ieee80211_sta *sta; + u8 paprd; }; -#define ATH_TX_ERROR 0x01 /** * @txq_map: Index is mac80211 queue number. This is @@ -289,7 +285,6 @@ struct ath_tx_control { * (axq_qnum). */ struct ath_tx { - u16 seq_no; u32 txqsetup; spinlock_t txbuflock; struct list_head txbuf; @@ -297,7 +292,6 @@ struct ath_tx { struct ath_descdma txdma; struct ath_txq *txq_map[IEEE80211_NUM_ACS]; struct ath_txq *uapsdq; - u32 txq_max_pending[IEEE80211_NUM_ACS]; u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32]; }; @@ -312,25 +306,280 @@ struct ath_rx { bool discard_next; u32 *rxlink; u32 num_pkts; - unsigned int rxfilter; struct list_head rxbuf; struct ath_descdma rxdma; struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; + struct ath_rxbuf *buf_hold; struct sk_buff *frag; u32 ampdu_ref; }; -int ath_startrecv(struct ath_softc *sc); +/*******************/ +/* Channel Context */ +/*******************/ + +struct ath_acq { + struct list_head acq_new; + struct list_head acq_old; + spinlock_t lock; +}; + +struct ath_chanctx { + struct cfg80211_chan_def chandef; + struct list_head vifs; + struct ath_acq acq[IEEE80211_NUM_ACS]; + int hw_queue_base; + + /* do not dereference, use for comparison only */ + struct ieee80211_vif *primary_sta; + + struct ath_beacon_config beacon; + struct ath9k_hw_cal_data caldata; + ktime_t tsf_ts; + u64 tsf_val; + u32 last_beacon; + + int flush_timeout; + u16 txpower; + u16 cur_txpower; + bool offchannel; + bool stopped; + bool active; + bool assigned; + bool switch_after_beacon; + + short nvifs; + short nvifs_assigned; + unsigned int rxfilter; +}; + +enum ath_chanctx_event { + ATH_CHANCTX_EVENT_BEACON_PREPARE, + ATH_CHANCTX_EVENT_BEACON_SENT, + ATH_CHANCTX_EVENT_TSF_TIMER, + ATH_CHANCTX_EVENT_BEACON_RECEIVED, + ATH_CHANCTX_EVENT_AUTHORIZED, + ATH_CHANCTX_EVENT_SWITCH, + ATH_CHANCTX_EVENT_ASSIGN, + ATH_CHANCTX_EVENT_UNASSIGN, + ATH_CHANCTX_EVENT_CHANGE, + ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL, +}; + +enum ath_chanctx_state { + ATH_CHANCTX_STATE_IDLE, + ATH_CHANCTX_STATE_WAIT_FOR_BEACON, + ATH_CHANCTX_STATE_WAIT_FOR_TIMER, + ATH_CHANCTX_STATE_SWITCH, + ATH_CHANCTX_STATE_FORCE_ACTIVE, +}; + +struct ath_chanctx_sched { + bool beacon_pending; + bool beacon_adjust; + bool offchannel_pending; + bool wait_switch; + bool force_noa_update; + bool extend_absence; + bool mgd_prepare_tx; + enum ath_chanctx_state state; + u8 beacon_miss; + + u32 next_tbtt; + u32 switch_start_time; + unsigned int offchannel_duration; + unsigned int channel_switch_time; + + /* backup, in case the hardware timer fails */ + struct timer_list timer; +}; + +enum ath_offchannel_state { + ATH_OFFCHANNEL_IDLE, + ATH_OFFCHANNEL_PROBE_SEND, + ATH_OFFCHANNEL_PROBE_WAIT, + ATH_OFFCHANNEL_SUSPEND, + ATH_OFFCHANNEL_ROC_START, + ATH_OFFCHANNEL_ROC_WAIT, + ATH_OFFCHANNEL_ROC_DONE, +}; + +enum ath_roc_complete_reason { + ATH_ROC_COMPLETE_EXPIRE, + ATH_ROC_COMPLETE_ABORT, + ATH_ROC_COMPLETE_CANCEL, +}; + +struct ath_offchannel { + struct ath_chanctx chan; + struct timer_list timer; + struct cfg80211_scan_request *scan_req; + struct ieee80211_vif *scan_vif; + int scan_idx; + enum ath_offchannel_state state; + struct ieee80211_channel *roc_chan; + struct ieee80211_vif *roc_vif; + int roc_duration; + int duration; +}; + +static inline struct ath_atx_tid * +ath_node_to_tid(struct ath_node *an, u8 tidno) +{ + struct ieee80211_sta *sta = an->sta; + struct ieee80211_vif *vif = an->vif; + struct ieee80211_txq *txq; + + BUG_ON(!vif); + if (sta) + txq = sta->txq[tidno % ARRAY_SIZE(sta->txq)]; + else + txq = vif->txq; + + return (struct ath_atx_tid *) txq->drv_priv; +} + +#define case_rtn_string(val) case val: return #val + +#define ath_for_each_chanctx(_sc, _ctx) \ + for (ctx = &sc->chanctx[0]; \ + ctx <= &sc->chanctx[ARRAY_SIZE(sc->chanctx) - 1]; \ + ctx++) + +void ath_chanctx_init(struct ath_softc *sc); +void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, + struct cfg80211_chan_def *chandef); + +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + +static inline struct ath_chanctx * +ath_chanctx_get(struct ieee80211_chanctx_conf *ctx) +{ + struct ath_chanctx **ptr = (void *) ctx->drv_priv; + return *ptr; +} + +bool ath9k_is_chanctx_enabled(void); +void ath9k_fill_chanctx_ops(void); +void ath9k_init_channel_context(struct ath_softc *sc); +void ath9k_offchannel_init(struct ath_softc *sc); +void ath9k_deinit_channel_context(struct ath_softc *sc); +int ath9k_init_p2p(struct ath_softc *sc); +void ath9k_deinit_p2p(struct ath_softc *sc); +void ath9k_p2p_remove_vif(struct ath_softc *sc, + struct ieee80211_vif *vif); +void ath9k_p2p_beacon_sync(struct ath_softc *sc); +void ath9k_p2p_bss_info_changed(struct ath_softc *sc, + struct ieee80211_vif *vif); +void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, + struct sk_buff *skb); +void ath9k_p2p_ps_timer(void *priv); +void ath9k_chanctx_wake_queues(struct ath_softc *sc, struct ath_chanctx *ctx); +void ath9k_chanctx_stop_queues(struct ath_softc *sc, struct ath_chanctx *ctx); +void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx); + +void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, + enum ath_chanctx_event ev); +void ath_chanctx_beacon_sent_ev(struct ath_softc *sc, + enum ath_chanctx_event ev); +void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, + enum ath_chanctx_event ev); +void ath_chanctx_set_next(struct ath_softc *sc, bool force); +void ath_offchannel_next(struct ath_softc *sc); +void ath_scan_complete(struct ath_softc *sc, bool abort); +void ath_roc_complete(struct ath_softc *sc, + enum ath_roc_complete_reason reason); +struct ath_chanctx* ath_is_go_chanctx_present(struct ath_softc *sc); + +#else + +static inline bool ath9k_is_chanctx_enabled(void) +{ + return false; +} +static inline void ath9k_fill_chanctx_ops(void) +{ +} +static inline void ath9k_init_channel_context(struct ath_softc *sc) +{ +} +static inline void ath9k_offchannel_init(struct ath_softc *sc) +{ +} +static inline void ath9k_deinit_channel_context(struct ath_softc *sc) +{ +} +static inline void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, + enum ath_chanctx_event ev) +{ +} +static inline void ath_chanctx_beacon_sent_ev(struct ath_softc *sc, + enum ath_chanctx_event ev) +{ +} +static inline void ath_chanctx_event(struct ath_softc *sc, + struct ieee80211_vif *vif, + enum ath_chanctx_event ev) +{ +} +static inline int ath9k_init_p2p(struct ath_softc *sc) +{ + return 0; +} +static inline void ath9k_deinit_p2p(struct ath_softc *sc) +{ +} +static inline void ath9k_p2p_remove_vif(struct ath_softc *sc, + struct ieee80211_vif *vif) +{ +} +static inline void ath9k_p2p_beacon_sync(struct ath_softc *sc) +{ +} +static inline void ath9k_p2p_bss_info_changed(struct ath_softc *sc, + struct ieee80211_vif *vif) +{ +} +static inline void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, + struct sk_buff *skb) +{ +} +static inline void ath9k_p2p_ps_timer(struct ath_softc *sc) +{ +} +static inline void ath9k_chanctx_wake_queues(struct ath_softc *sc, + struct ath_chanctx *ctx) +{ +} +static inline void ath9k_chanctx_stop_queues(struct ath_softc *sc, + struct ath_chanctx *ctx) +{ +} +static inline void ath_chanctx_check_active(struct ath_softc *sc, + struct ath_chanctx *ctx) +{ +} + +#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ + +static inline void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq) +{ + spin_lock_bh(&txq->axq_lock); +} +static inline void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq) +{ + spin_unlock_bh(&txq->axq_lock); +} + +void ath_startrecv(struct ath_softc *sc); bool ath_stoprecv(struct ath_softc *sc); u32 ath_calcrxfilter(struct ath_softc *sc); int ath_rx_init(struct ath_softc *sc, int nbufs); void ath_rx_cleanup(struct ath_softc *sc); int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp); struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype); -void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq); -void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq); void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq); void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); bool ath_drain_all_txq(struct ath_softc *sc); @@ -338,10 +587,14 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq); void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); +void ath_txq_schedule_all(struct ath_softc *sc); int ath_tx_init(struct ath_softc *sc, int nbufs); int ath_txq_update(struct ath_softc *sc, int qnum, struct ath9k_tx_queue_info *q); +u32 ath_pkt_duration(u8 rix, int pktlen, int width, + int half_gi, bool shortPreamble); void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop); +void ath_assign_seq(struct ath_common *common, struct sk_buff *skb); int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_tx_control *txctl); void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -351,7 +604,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc); int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid, u16 *ssn); void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); -void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an); void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, @@ -361,18 +613,70 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, u16 tids, int nframes, enum ieee80211_frame_release_type reason, bool more_data); +void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue); /********/ /* VIFs */ /********/ +#define P2P_DEFAULT_CTWIN 10 + struct ath_vif { + struct list_head list; + + u16 seq_no; + + /* BSS info */ + u8 bssid[ETH_ALEN] __aligned(2); + u16 aid; + bool assoc; + + struct ieee80211_vif *vif; + struct ath_node mcast_node; int av_bslot; - bool primary_sta_vif; __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ struct ath_buf *av_bcbuf; + struct ath_chanctx *chanctx; + + /* P2P Client */ + struct ieee80211_noa_data noa; + + /* P2P GO */ + u8 noa_index; + u32 offchannel_start; + u32 offchannel_duration; + + /* These are used for both periodic and one-shot */ + u32 noa_start; + u32 noa_duration; + bool periodic_noa; + bool oneshot_noa; +}; + +struct ath9k_vif_iter_data { + u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */ + u8 mask[ETH_ALEN]; /* bssid mask */ + bool has_hw_macaddr; + u8 slottime; + bool beacons; + + int naps; /* number of AP vifs */ + int nmeshes; /* number of mesh vifs */ + int nstations; /* number of station vifs */ + int nadhocs; /* number of adhoc vifs */ + int nocbs; /* number of OCB vifs */ + int nbcnvifs; /* number of beaconing vifs */ + struct ieee80211_vif *primary_beacon_vif; + struct ieee80211_vif *primary_sta; }; +void ath9k_calculate_iter_data(struct ath_softc *sc, + struct ath_chanctx *ctx, + struct ath9k_vif_iter_data *iter_data); +void ath9k_calculate_summary_state(struct ath_softc *sc, + struct ath_chanctx *ctx); +void ath9k_set_txpower(struct ath_softc *sc, struct ieee80211_vif *vif); + /*******************/ /* Beacon Handling */ /*******************/ @@ -386,17 +690,9 @@ struct ath_vif { #define ATH_BCBUF 8 #define ATH_DEFAULT_BINTVAL 100 /* TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 -#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) - -struct ath_beacon_config { - int beacon_interval; - u16 listen_interval; - u16 dtim_period; - u16 bmiss_timeout; - u8 dtim_count; - bool enable_beacon; - bool ibss_creator; -}; + +#define TSF_TO_TU(_h,_l) \ + ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) struct ath_beacon { enum { @@ -407,11 +703,9 @@ struct ath_beacon { u32 beaconq; u32 bmisscnt; - u32 bc_tstamp; struct ieee80211_vif *bslot[ATH_BCBUF]; int slottime; int slotupdate; - struct ath9k_tx_queue_info beacon_qi; struct ath_descdma bdma; struct ath_txq *cabq; struct list_head bbuf; @@ -420,14 +714,15 @@ struct ath_beacon { bool tx_last; }; -void ath9k_beacon_tasklet(unsigned long data); -bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); -void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, - u32 changed); +void ath9k_beacon_tasklet(struct tasklet_struct *t); +void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif, + bool beacons); void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif); void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif); -void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif); +void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc); void ath9k_set_beacon(struct ath_softc *sc); +bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif); +void ath9k_csa_update(struct ath_softc *sc); /*******************/ /* Link Monitoring */ @@ -440,25 +735,25 @@ void ath9k_set_beacon(struct ath_softc *sc); #define ATH_LONG_CALINTERVAL_INT 1000 /* 1000 ms */ #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ -#define ATH_ANI_MAX_SKIP_COUNT 10 +#define ATH_ANI_MAX_SKIP_COUNT 10 +#define ATH_PAPRD_TIMEOUT 100 /* msecs */ +#define ATH_PLL_WORK_INTERVAL 100 -#define ATH_PAPRD_TIMEOUT 100 /* msecs */ -#define ATH_PLL_WORK_INTERVAL 100 - -void ath_tx_complete_poll_work(struct work_struct *work); +void ath_hw_check_work(struct work_struct *work); void ath_reset_work(struct work_struct *work); -void ath_hw_check(struct work_struct *work); +bool ath_hw_check(struct ath_softc *sc); void ath_hw_pll_work(struct work_struct *work); -void ath_rx_poll(unsigned long data); -void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon); void ath_paprd_calibrate(struct work_struct *work); -void ath_ani_calibrate(unsigned long data); +void ath_ani_calibrate(struct timer_list *t); void ath_start_ani(struct ath_softc *sc); void ath_stop_ani(struct ath_softc *sc); void ath_check_ani(struct ath_softc *sc); int ath_update_survey_stats(struct ath_softc *sc); void ath_update_survey_nf(struct ath_softc *sc, int channel); void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); +void ath_ps_full_sleep(struct timer_list *t); +void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop, + bool sw_pending, bool timeout_override); /**********/ /* BTCOEX */ @@ -466,8 +761,8 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); #define ATH_DUMP_BTCOEX(_s, _val) \ do { \ - len += snprintf(buf + len, size - len, \ - "%20s : %10d\n", _s, (_val)); \ + len += scnprintf(buf + len, size - len, \ + "%20s : %10d\n", _s, (_val)); \ } while (0) enum bt_op_flags { @@ -476,20 +771,19 @@ enum bt_op_flags { }; struct ath_btcoex { - bool hw_timer_enabled; spinlock_t btcoex_lock; struct timer_list period_timer; /* Timer for BT period */ + struct timer_list no_stomp_timer; u32 bt_priority_cnt; unsigned long bt_priority_time; unsigned long op_flags; int bt_stomp_type; /* Types of BT stomping */ - u32 btcoex_no_stomp; /* in usec */ + u32 btcoex_no_stomp; /* in msec */ u32 btcoex_period; /* in msec */ - u32 btscan_no_stomp; /* in usec */ + u32 btscan_no_stomp; /* in msec */ u32 duty_cycle; u32 bt_wait_time; int rssi_count; - struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ struct ath_mci_profile mci; u8 stomp_audio; }; @@ -537,12 +831,6 @@ static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size) } #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ -struct ath9k_wow_pattern { - u8 pattern_bytes[MAX_PATTERN_SIZE]; - u8 mask_bytes[MAX_PATTERN_SIZE]; - u32 pattern_len; -}; - /********************/ /* LED Control */ /********************/ @@ -556,7 +844,6 @@ struct ath9k_wow_pattern { #ifdef CONFIG_MAC80211_LEDS void ath_init_leds(struct ath_softc *sc); void ath_deinit_leds(struct ath_softc *sc); -void ath_fill_led_pin(struct ath_softc *sc); #else static inline void ath_init_leds(struct ath_softc *sc) { @@ -565,10 +852,39 @@ static inline void ath_init_leds(struct ath_softc *sc) static inline void ath_deinit_leds(struct ath_softc *sc) { } -static inline void ath_fill_led_pin(struct ath_softc *sc) +#endif + +/************************/ +/* Wake on Wireless LAN */ +/************************/ + +#ifdef CONFIG_ATH9K_WOW +void ath9k_init_wow(struct ieee80211_hw *hw); +void ath9k_deinit_wow(struct ieee80211_hw *hw); +int ath9k_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan); +int ath9k_resume(struct ieee80211_hw *hw); +void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled); +#else +static inline void ath9k_init_wow(struct ieee80211_hw *hw) { } -#endif +static inline void ath9k_deinit_wow(struct ieee80211_hw *hw) +{ +} +static inline int ath9k_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) +{ + return 0; +} +static inline int ath9k_resume(struct ieee80211_hw *hw) +{ + return 0; +} +static inline void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) +{ +} +#endif /* CONFIG_ATH9K_WOW */ /*******************************/ /* Antenna diversity/combining */ @@ -585,19 +901,13 @@ static inline void ath_fill_led_pin(struct ath_softc *sc) #define ATH_ANT_DIV_COMB_MAX_COUNT 100 #define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30 #define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20 +#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI 50 +#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI 50 -#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1 #define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4 #define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2 #define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2 -enum ath9k_ant_div_comb_lna_conf { - ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2, - ATH_ANT_DIV_COMB_LNA2, - ATH_ANT_DIV_COMB_LNA1, - ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2, -}; - struct ath_ant_comb { u16 count; u16 total_pkt_count; @@ -614,49 +924,51 @@ struct ath_ant_comb { int rssi_first; int rssi_second; int rssi_third; + int ant_ratio; + int ant_ratio2; bool alt_good; int quick_scan_cnt; - int main_conf; + enum ath9k_ant_div_comb_lna_conf main_conf; enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf; enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf; bool first_ratio; bool second_ratio; unsigned long scan_start_time; + + /* + * Card-specific config values. + */ + int low_rssi_thresh; + int fast_div_bias; }; void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); -void ath_ant_comb_update(struct ath_softc *sc); /********************/ /* Main driver core */ /********************/ -#define ATH9K_PCI_CUS198 0x0001 -#define ATH9K_PCI_CUS230 0x0002 -#define ATH9K_PCI_CUS217 0x0004 -#define ATH9K_PCI_WOW 0x0008 +#define ATH9K_PCI_CUS198 0x0001 +#define ATH9K_PCI_CUS230 0x0002 +#define ATH9K_PCI_CUS217 0x0004 +#define ATH9K_PCI_CUS252 0x0008 +#define ATH9K_PCI_WOW 0x0010 +#define ATH9K_PCI_BT_ANT_DIV 0x0020 +#define ATH9K_PCI_D3_L1_WAR 0x0040 +#define ATH9K_PCI_AR9565_1ANT 0x0080 +#define ATH9K_PCI_AR9565_2ANT 0x0100 +#define ATH9K_PCI_NO_PLL_PWRSAVE 0x0200 +#define ATH9K_PCI_KILLER 0x0400 +#define ATH9K_PCI_LED_ACT_HI 0x0800 /* * Default cache line size, in bytes. * Used when PCI device not fully initialized by bootrom/BIOS */ #define DEFAULT_CACHELINE 32 -#define ATH_REGCLASSIDS_MAX 10 #define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ -#define ATH_MAX_SW_RETRIES 30 -#define ATH_CHAN_MAX 255 - #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ -#define ATH_RATE_DUMMY_MARKER 0 - -enum sc_op_flags { - SC_OP_INVALID, - SC_OP_BEACONS, - SC_OP_ANI_RUN, - SC_OP_PRIM_STA_VIF, - SC_OP_HW_RESET, - SC_OP_SCANNING, -}; +#define MAX_GTT_CNT 5 /* Powersave flags */ #define PS_WAIT_FOR_BEACON BIT(0) @@ -666,36 +978,7 @@ enum sc_op_flags { #define PS_BEACON_SYNC BIT(4) #define PS_WAIT_FOR_ANI BIT(5) -struct ath_rate_table; - -struct ath9k_vif_iter_data { - u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */ - u8 mask[ETH_ALEN]; /* bssid mask */ - bool has_hw_macaddr; - - int naps; /* number of AP vifs */ - int nmeshes; /* number of mesh vifs */ - int nstations; /* number of station vifs */ - int nwds; /* number of WDS vifs */ - int nadhocs; /* number of adhoc vifs */ -}; - -/* enum spectral_mode: - * - * @SPECTRAL_DISABLED: spectral mode is disabled - * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with - * something else. - * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples - * is performed manually. - * @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels - * during a channel scan. - */ -enum spectral_mode { - SPECTRAL_DISABLED = 0, - SPECTRAL_BACKGROUND, - SPECTRAL_MANUAL, - SPECTRAL_CHANSCAN, -}; +#define ATH9K_NUM_CHANCTX 2 /* supports 2 operating channels */ struct ath_softc { struct ieee80211_hw *hw; @@ -704,6 +987,7 @@ struct ath_softc { struct survey_info *cur_survey; struct survey_info survey[ATH9K_NUM_CHANNELS]; + spinlock_t intr_lock; struct tasklet_struct intr_tq; struct tasklet_struct bcon_tasklet; struct ath_hw *sc_ah; @@ -714,28 +998,41 @@ struct ath_softc { spinlock_t sc_pcu_lock; struct mutex mutex; struct work_struct paprd_work; - struct work_struct hw_check_work; struct work_struct hw_reset_work; struct completion paprd_complete; + wait_queue_head_t tx_wait; + +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + struct work_struct chanctx_work; + struct ath_gen_timer *p2p_ps_timer; + struct ath_vif *p2p_ps_vif; + struct ath_chanctx_sched sched; + struct ath_offchannel offchannel; + struct ath_chanctx *next_chan; + struct completion go_beacon; + ktime_t last_event_time; +#endif - unsigned int hw_busy_count; - unsigned long sc_flags; unsigned long driver_data; + u8 gtt_cnt; u32 intrstatus; + unsigned long rx_active_check_time; + u32 rx_active_count; u16 ps_flags; /* PS_* */ - u16 curtxpow; bool ps_enabled; bool ps_idle; short nbcnvifs; - short nvifs; unsigned long ps_usecount; - struct ath_config config; struct ath_rx rx; struct ath_tx tx; struct ath_beacon beacon; - struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; + + struct cfg80211_chan_def cur_chandef; + struct ath_chanctx chanctx[ATH9K_NUM_CHANCTX]; + struct ath_chanctx *cur_chan; + spinlock_t chan_lock; #ifdef CONFIG_MAC80211_LEDS bool led_registered; @@ -743,16 +1040,12 @@ struct ath_softc { struct led_classdev led_cdev; #endif - struct ath9k_hw_cal_data caldata; - int last_rssi; - #ifdef CONFIG_ATH9K_DEBUGFS struct ath9k_debug debug; #endif - struct ath_beacon_config cur_beacon_conf; - struct delayed_work tx_complete_work; + struct delayed_work hw_check_work; struct delayed_work hw_pll_work; - struct timer_list rx_poll_timer; + struct timer_list sleep_timer; #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT struct ath_btcoex btcoex; @@ -765,172 +1058,84 @@ struct ath_softc { struct ath_ant_comb ant_comb; u8 ant_tx, ant_rx; struct dfs_pattern_detector *dfs_detector; + u64 dfs_prev_pulse_ts; u32 wow_enabled; - /* relay(fs) channel for spectral scan */ - struct rchan *rfs_chan_spec_scan; - enum spectral_mode spectral_mode; - struct ath_spec_scan spec_config; - -#ifdef CONFIG_PM_SLEEP - atomic_t wow_got_bmiss_intr; - atomic_t wow_sleep_proc_intr; /* in the middle of WoW sleep ? */ - u32 wow_intr_before_sleep; -#endif -}; - -#define SPECTRAL_SCAN_BITMASK 0x10 -/* Radar info packet format, used for DFS and spectral formats. */ -struct ath_radar_info { - u8 pulse_length_pri; - u8 pulse_length_ext; - u8 pulse_bw_info; -} __packed; -/* The HT20 spectral data has 4 bytes of additional information at it's end. - * - * [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]} - * [7:0]: all bins max_magnitude[9:2] - * [7:0]: all bins {max_index[5:0], max_magnitude[11:10]} - * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned) - */ -struct ath_ht20_mag_info { - u8 all_bins[3]; - u8 max_exp; -} __packed; - -#define SPECTRAL_HT20_NUM_BINS 56 - -/* WARNING: don't actually use this struct! MAC may vary the amount of - * data by -1/+2. This struct is for reference only. - */ -struct ath_ht20_fft_packet { - u8 data[SPECTRAL_HT20_NUM_BINS]; - struct ath_ht20_mag_info mag_info; - struct ath_radar_info radar_info; -} __packed; + struct ath_spec_scan_priv spec_priv; -#define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ath_ht20_fft_packet)) + struct ieee80211_vif *tx99_vif; + struct sk_buff *tx99_skb; + bool tx99_state; + s16 tx99_power; -/* Dynamic 20/40 mode: - * - * [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]} - * [7:0]: lower bins max_magnitude[9:2] - * [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]} - * [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]} - * [7:0]: upper bins max_magnitude[9:2] - * [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]} - * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned) - */ -struct ath_ht20_40_mag_info { - u8 lower_bins[3]; - u8 upper_bins[3]; - u8 max_exp; -} __packed; - -#define SPECTRAL_HT20_40_NUM_BINS 128 - -/* WARNING: don't actually use this struct! MAC may vary the amount of - * data. This struct is for reference only. - */ -struct ath_ht20_40_fft_packet { - u8 data[SPECTRAL_HT20_40_NUM_BINS]; - struct ath_ht20_40_mag_info mag_info; - struct ath_radar_info radar_info; -} __packed; +#ifdef CONFIG_ATH9K_WOW + u32 wow_intr_before_sleep; + bool force_wow; +#endif +#ifdef CONFIG_ATH9K_HWRNG + struct hwrng rng_ops; + u32 rng_last; + char rng_name[sizeof("ath9k_65535")]; +#endif +}; -#define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet)) +/********/ +/* TX99 */ +/********/ -/* grabs the max magnitude from the all/upper/lower bins */ -static inline u16 spectral_max_magnitude(u8 *bins) +#ifdef CONFIG_ATH9K_TX99 +void ath9k_tx99_init_debug(struct ath_softc *sc); +int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, + struct ath_tx_control *txctl); +#else +static inline void ath9k_tx99_init_debug(struct ath_softc *sc) { - return (bins[0] & 0xc0) >> 6 | - (bins[1] & 0xff) << 2 | - (bins[2] & 0x03) << 10; } - -/* return the max magnitude from the all/upper/lower bins */ -static inline u8 spectral_max_index(u8 *bins) +static inline int ath9k_tx99_send(struct ath_softc *sc, + struct sk_buff *skb, + struct ath_tx_control *txctl) { - s8 m = (bins[2] & 0xfc) >> 2; - - /* TODO: this still doesn't always report the right values ... */ - if (m > 32) - m |= 0xe0; - else - m &= ~0xe0; - - return m + 29; + return 0; } - -/* return the bitmap weight from the all/upper/lower bins */ -static inline u8 spectral_bitmap_weight(u8 *bins) +#endif /* CONFIG_ATH9K_TX99 */ + +/***************************/ +/* Random Number Generator */ +/***************************/ +#ifdef CONFIG_ATH9K_HWRNG +void ath9k_rng_start(struct ath_softc *sc); +void ath9k_rng_stop(struct ath_softc *sc); +#else +static inline void ath9k_rng_start(struct ath_softc *sc) { - return bins[0] & 0x3f; } -/* FFT sample format given to userspace via debugfs. - * - * Please keep the type/length at the front position and change - * other fields after adding another sample type - * - * TODO: this might need rework when switching to nl80211-based - * interface. - */ -enum ath_fft_sample_type { - ATH_FFT_SAMPLE_HT20 = 1, -}; - -struct fft_sample_tlv { - u8 type; /* see ath_fft_sample */ - __be16 length; - /* type dependent data follows */ -} __packed; - -struct fft_sample_ht20 { - struct fft_sample_tlv tlv; - - u8 max_exp; - - __be16 freq; - s8 rssi; - s8 noise; - - __be16 max_magnitude; - u8 max_index; - u8 bitmap_weight; - - __be64 tsf; - - u8 data[SPECTRAL_HT20_NUM_BINS]; -} __packed; - -void ath9k_tasklet(unsigned long data); -int ath_cabq_update(struct ath_softc *); +static inline void ath9k_rng_stop(struct ath_softc *sc) +{ +} +#endif static inline void ath_read_cachesize(struct ath_common *common, int *csz) { common->bus_ops->read_cachesize(common, csz); } -extern struct ieee80211_ops ath9k_ops; -extern int ath9k_modparam_nohwcrypt; -extern int led_blink; -extern bool is_ath9k_unloaded; - +void ath9k_tasklet(struct tasklet_struct *t); +int ath_cabq_update(struct ath_softc *); u8 ath9k_parse_mpdudensity(u8 mpdudensity); irqreturn_t ath_isr(int irq, void *dev); +int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan); +void ath_cancel_work(struct ath_softc *sc); +void ath_restart_work(struct ath_softc *sc); int ath9k_init_device(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops); void ath9k_deinit_device(struct ath_softc *sc); -void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); -void ath9k_reload_chainmask_settings(struct ath_softc *sc); - -bool ath9k_uses_beacons(int type); -void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw); -int ath9k_spectral_scan_config(struct ieee80211_hw *hw, - enum spectral_mode spectral_mode); - +u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate); +void ath_start_rfkill_poll(struct ath_softc *sc); +void ath9k_rfkill_poll_state(struct ieee80211_hw *hw); +void ath9k_ps_wakeup(struct ath_softc *sc); +void ath9k_ps_restore(struct ath_softc *sc); #ifdef CONFIG_ATH9K_PCI int ath_pci_init(void); @@ -948,15 +1153,4 @@ static inline int ath_ahb_init(void) { return 0; }; static inline void ath_ahb_exit(void) {}; #endif -void ath9k_ps_wakeup(struct ath_softc *sc); -void ath9k_ps_restore(struct ath_softc *sc); - -u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate); - -void ath_start_rfkill_poll(struct ath_softc *sc); -extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw); -void ath9k_calculate_iter_data(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ath9k_vif_iter_data *iter_data); - #endif /* ATH9K_H */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c new file mode 100644 index 000000000000..fe1013a3a588 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: ISC +/* Initialize Owl Emulation Devices + * + * Copyright (C) 2016 Christian Lamparter <chunkeey@gmail.com> + * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com> + * + * Some devices (like the Cisco Meraki Z1 Cloud Managed Teleworker Gateway) + * need to be able to initialize the PCIe wifi device. Normally, this is done + * during the early stages as a pci quirk. + * However, this isn't possible for devices which have the init code for the + * Atheros chip stored on UBI Volume on NAND. Hence, this module can be used to + * initialize the chip when the user-space is ready to extract the init code. + */ +#include <linux/module.h> +#include <linux/completion.h> +#include <linux/etherdevice.h> +#include <linux/firmware.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/nvmem-consumer.h> +#include <linux/workqueue.h> + +struct owl_ctx { + struct pci_dev *pdev; + struct completion eeprom_load; + struct work_struct work; + struct nvmem_cell *cell; +}; + +#define EEPROM_FILENAME_LEN 100 + +#define AR5416_EEPROM_MAGIC 0xa55a + +static int ath9k_pci_fixup(struct pci_dev *pdev, const u16 *cal_data, + size_t cal_len) +{ + void __iomem *mem; + const void *cal_end = (void *)cal_data + cal_len; + const struct { + u16 reg; + u16 low_val; + u16 high_val; + } __packed * data; + u16 cmd; + u32 bar0; + bool swap_needed = false; + + /* also note that we are doing *u16 operations on the file */ + if (cal_len > 4096 || cal_len < 0x200 || (cal_len & 1) == 1) { + dev_err(&pdev->dev, "eeprom has an invalid size.\n"); + return -EINVAL; + } + + if (*cal_data != AR5416_EEPROM_MAGIC) { + if (*cal_data != swab16(AR5416_EEPROM_MAGIC)) { + dev_err(&pdev->dev, "invalid calibration data\n"); + return -EINVAL; + } + + dev_dbg(&pdev->dev, "calibration data needs swapping\n"); + swap_needed = true; + } + + dev_info(&pdev->dev, "fixup device configuration\n"); + + mem = pci_iomap(pdev, 0, 0); + if (!mem) { + dev_err(&pdev->dev, "ioremap error\n"); + return -EINVAL; + } + + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0); + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, + pci_resource_start(pdev, 0)); + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; + pci_write_config_word(pdev, PCI_COMMAND, cmd); + + /* set pointer to first reg address */ + for (data = (const void *)(cal_data + 3); + (const void *)data <= cal_end && data->reg != (u16)~0; + data++) { + u32 val; + u16 reg; + + reg = data->reg; + val = data->low_val; + val |= ((u32)data->high_val) << 16; + + if (swap_needed) { + reg = swab16(reg); + val = swahb32(val); + } + + iowrite32(val, mem + reg); + usleep_range(100, 120); + } + + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + pci_write_config_word(pdev, PCI_COMMAND, cmd); + + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, bar0); + pci_iounmap(pdev, mem); + + pci_disable_device(pdev); + + return 0; +} + +static void owl_rescan(struct pci_dev *pdev) +{ + struct pci_bus *bus = pdev->bus; + + pci_lock_rescan_remove(); + pci_stop_and_remove_bus_device(pdev); + /* the device should come back with the proper + * ProductId. But we have to initiate a rescan. + */ + pci_rescan_bus(bus); + pci_unlock_rescan_remove(); +} + +static void owl_fw_cb(const struct firmware *fw, void *context) +{ + struct owl_ctx *ctx = context; + + complete(&ctx->eeprom_load); + + if (fw) { + ath9k_pci_fixup(ctx->pdev, (const u16 *)fw->data, fw->size); + owl_rescan(ctx->pdev); + } else { + dev_err(&ctx->pdev->dev, "no eeprom data received.\n"); + } + release_firmware(fw); +} + +static const char *owl_get_eeprom_name(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + char *eeprom_name; + + dev_dbg(dev, "using auto-generated eeprom filename\n"); + + eeprom_name = devm_kzalloc(dev, EEPROM_FILENAME_LEN, GFP_KERNEL); + if (!eeprom_name) + return NULL; + + /* this should match the pattern used in ath9k/init.c */ + scnprintf(eeprom_name, EEPROM_FILENAME_LEN, "ath9k-eeprom-pci-%s.bin", + dev_name(dev)); + + return eeprom_name; +} + +static void owl_nvmem_work(struct work_struct *work) +{ + struct owl_ctx *ctx = container_of(work, struct owl_ctx, work); + void *buf; + size_t len; + + complete(&ctx->eeprom_load); + + buf = nvmem_cell_read(ctx->cell, &len); + if (!IS_ERR(buf)) { + ath9k_pci_fixup(ctx->pdev, buf, len); + kfree(buf); + owl_rescan(ctx->pdev); + } else { + dev_err(&ctx->pdev->dev, "no nvmem data received.\n"); + } +} + +static int owl_nvmem_probe(struct owl_ctx *ctx) +{ + int err; + + ctx->cell = devm_nvmem_cell_get(&ctx->pdev->dev, "calibration"); + if (IS_ERR(ctx->cell)) { + err = PTR_ERR(ctx->cell); + if (err == -ENOENT || err == -EOPNOTSUPP) + return 1; /* not present, try firmware_request */ + + return err; + } + + INIT_WORK(&ctx->work, owl_nvmem_work); + schedule_work(&ctx->work); + + return 0; +} + +static int owl_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct owl_ctx *ctx; + const char *eeprom_name; + int err = 0; + + if (pci_enable_device(pdev)) + return -EIO; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + init_completion(&ctx->eeprom_load); + ctx->pdev = pdev; + + pci_set_drvdata(pdev, ctx); + + err = owl_nvmem_probe(ctx); + if (err <= 0) + return err; + + eeprom_name = owl_get_eeprom_name(pdev); + if (!eeprom_name) { + dev_err(&pdev->dev, "no eeprom filename found.\n"); + return -ENODEV; + } + + err = request_firmware_nowait(THIS_MODULE, true, eeprom_name, + &pdev->dev, GFP_KERNEL, ctx, owl_fw_cb); + if (err) + dev_err(&pdev->dev, "failed to request caldata (%d).\n", err); + + return err; +} + +static void owl_remove(struct pci_dev *pdev) +{ + struct owl_ctx *ctx = pci_get_drvdata(pdev); + + if (ctx) { + wait_for_completion(&ctx->eeprom_load); + pci_set_drvdata(pdev, NULL); + } +} + +static const struct pci_device_id owl_pci_table[] = { + { PCI_VDEVICE(ATHEROS, 0xff1c) }, /* PCIe */ + { PCI_VDEVICE(ATHEROS, 0xff1d) }, /* PCI */ + { }, +}; +MODULE_DEVICE_TABLE(pci, owl_pci_table); + +static struct pci_driver owl_driver = { + .name = KBUILD_MODNAME, + .id_table = owl_pci_table, + .probe = owl_probe, + .remove = owl_remove, +}; +module_pci_driver(owl_driver); +MODULE_AUTHOR("Christian Lamparter <chunkeey@gmail.com>"); +MODULE_DESCRIPTION("External EEPROM data loader for Atheros AR500X to AR92XX"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 1a17732bb089..4a27e3753c03 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -50,7 +50,7 @@ static void ath9k_beaconq_config(struct ath_softc *sc) txq = sc->tx.txq_map[IEEE80211_AC_BE]; ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be); qi.tqi_aifs = qi_be.tqi_aifs; - if (ah->slottime == ATH9K_SLOT_TIME_20) + if (ah->slottime == 20) qi.tqi_cwmin = 2*qi_be.tqi_cwmin; else qi.tqi_cwmin = 4*qi_be.tqi_cwmin; @@ -78,9 +78,9 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, struct ath_tx_info info; struct ieee80211_supported_band *sband; u8 chainmask = ah->txchainmask; - u8 rate = 0; + u8 i, rate = 0; - sband = &sc->sbands[common->hw->conf.chandef.chan->band]; + sband = &common->sbands[sc->cur_chandef.chan->band]; rate = sband->bitrates[rateidx].hw_value; if (vif->bss_conf.use_short_preamble) rate |= sband->bitrates[rateidx].hw_value_short; @@ -88,7 +88,8 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, memset(&info, 0, sizeof(info)); info.pkt_len = skb->len + FCS_LEN; info.type = ATH9K_PKT_TYPE_BEACON; - info.txpower = MAX_RATE_POWER; + for (i = 0; i < 4; i++) + info.txpower[i] = MAX_RATE_POWER; info.keyix = ATH9K_TXKEYIX_INVALID; info.keytype = ATH9K_KEY_TYPE_CLEAR; info.flags = ATH9K_TXDESC_NOACK | ATH9K_TXDESC_CLRDMASK; @@ -134,7 +135,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, bf->bf_mpdu = NULL; } - skb = ieee80211_beacon_get(hw, vif); + skb = ieee80211_beacon_get(hw, vif, 0); if (skb == NULL) return NULL; @@ -144,16 +145,12 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, mgmt_hdr->u.beacon.timestamp = avp->tsf_adjust; info = IEEE80211_SKB_CB(skb); - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - /* - * TODO: make sure the seq# gets assigned properly (vs. other - * TX frames) - */ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - sc->tx.seq_no += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); - } + + ath_assign_seq(common, skb); + + /* Always assign NOA attr when MCC enabled */ + if (ath9k_is_chanctx_enabled()) + ath9k_beacon_add_noa(sc, avp, skb); bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, skb->len, DMA_TO_DEVICE); @@ -180,7 +177,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, spin_unlock_bh(&cabq->axq_lock); if (skb && cabq_depth) { - if (sc->nvifs > 1) { + if (sc->cur_chan->nvifs > 1) { ath_dbg(common, BEACON, "Flushing previous cabq traffic\n"); ath_draintxq(sc, cabq); @@ -212,7 +209,6 @@ void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif) } sc->beacon.bslot[avp->av_bslot] = vif; - sc->nbcnvifs++; ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n", avp->av_bslot); @@ -240,16 +236,77 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif) avp->av_bcbuf = NULL; sc->beacon.bslot[avp->av_bslot] = NULL; - sc->nbcnvifs--; list_add_tail(&bf->list, &sc->beacon.bbuf); tasklet_enable(&sc->bcon_tasklet); } +void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_vif *vif; + struct ath_vif *avp; + s64 tsfadjust; + u32 offset; + int first_slot = ATH_BCBUF; + int slot; + + tasklet_disable_in_atomic(&sc->bcon_tasklet); + + /* Find first taken slot. */ + for (slot = 0; slot < ATH_BCBUF; slot++) { + if (sc->beacon.bslot[slot]) { + first_slot = slot; + break; + } + } + if (first_slot == 0) + goto out; + + /* Re-enumarate all slots, moving them forward. */ + for (slot = 0; slot < ATH_BCBUF; slot++) { + if (slot + first_slot < ATH_BCBUF) { + vif = sc->beacon.bslot[slot + first_slot]; + sc->beacon.bslot[slot] = vif; + + if (vif) { + avp = (void *)vif->drv_priv; + avp->av_bslot = slot; + } + } else { + sc->beacon.bslot[slot] = NULL; + } + } + + vif = sc->beacon.bslot[0]; + if (WARN_ON(!vif)) + goto out; + + /* Get the tsf_adjust value for the new first slot. */ + avp = (void *)vif->drv_priv; + tsfadjust = le64_to_cpu(avp->tsf_adjust); + + ath_dbg(common, CONFIG, + "Adjusting global TSF after beacon slot reassignment: %lld\n", + (signed long long)tsfadjust); + + /* Modify TSF as required and update the HW. */ + avp->chanctx->tsf_val += tsfadjust; + if (sc->cur_chan == avp->chanctx) { + offset = ath9k_hw_get_tsf_offset(avp->chanctx->tsf_ts, 0); + ath9k_hw_settsf64(sc->sc_ah, avp->chanctx->tsf_val + offset); + } + + /* The slots tsf_adjust will be updated by ath9k_beacon_config later. */ + +out: + tasklet_enable(&sc->bcon_tasklet); +} + static int ath9k_beacon_choose_slot(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; u16 intval; u32 tsftu; u64 tsf; @@ -274,26 +331,63 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc) return slot; } -void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif) +static void ath9k_set_tsfadjust(struct ath_softc *sc, + struct ath_beacon_config *cur_conf) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; - struct ath_vif *avp = (void *)vif->drv_priv; - u64 tsfadjust; + s64 tsfadjust; + int slot; - if (avp->av_bslot == 0) - return; + for (slot = 0; slot < ATH_BCBUF; slot++) { + struct ath_vif *avp; - tsfadjust = cur_conf->beacon_interval * avp->av_bslot / ATH_BCBUF; - avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); + if (!sc->beacon.bslot[slot]) + continue; - ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n", - (unsigned long long)tsfadjust, avp->av_bslot); + avp = (void *)sc->beacon.bslot[slot]->drv_priv; + + /* tsf_adjust is added to the TSF value. We send out the + * beacon late, so need to adjust the TSF starting point to be + * later in time (i.e. the theoretical first beacon has a TSF + * of 0 after correction). + */ + tsfadjust = cur_conf->beacon_interval * avp->av_bslot; + tsfadjust = -TU_TO_USEC(tsfadjust) / ATH_BCBUF; + avp->tsf_adjust = cpu_to_le64(tsfadjust); + + ath_dbg(common, CONFIG, "tsfadjust is: %lld for bslot: %d\n", + (signed long long)tsfadjust, avp->av_bslot); + } } -void ath9k_beacon_tasklet(unsigned long data) +bool ath9k_csa_is_finished(struct ath_softc *sc, struct ieee80211_vif *vif) { - struct ath_softc *sc = (struct ath_softc *)data; + if (!vif || !vif->bss_conf.csa_active) + return false; + + if (!ieee80211_beacon_cntdwn_is_complete(vif, 0)) + return false; + + ieee80211_csa_finish(vif, 0); + return true; +} + +static void ath9k_csa_update_vif(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath_softc *sc = data; + ath9k_csa_is_finished(sc, vif); +} + +void ath9k_csa_update(struct ath_softc *sc) +{ + ieee80211_iterate_active_interfaces_atomic(sc->hw, + IEEE80211_IFACE_ITER_NORMAL, + ath9k_csa_update_vif, sc); +} + +void ath9k_beacon_tasklet(struct tasklet_struct *t) +{ + struct ath_softc *sc = from_tasklet(sc, t, bcon_tasklet); struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_buf *bf = NULL; @@ -301,7 +395,7 @@ void ath9k_beacon_tasklet(unsigned long data) bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); int slot; - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) { + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) { ath_dbg(common, RESET, "reset work is pending, skip beaconing now\n"); return; @@ -317,8 +411,16 @@ void ath9k_beacon_tasklet(unsigned long data) if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { sc->beacon.bmisscnt++; - if (!ath9k_hw_check_alive(ah)) - ieee80211_queue_work(sc->hw, &sc->hw_check_work); + ath9k_hw_check_nav(ah); + + /* + * If the previous beacon has not been transmitted + * and a MAC/BB hang has been identified, return + * here because a chip reset would have been + * initiated. + */ + if (!ath_hw_check(sc)) + return; if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) { ath_dbg(common, BSTUCK, @@ -339,9 +441,24 @@ void ath9k_beacon_tasklet(unsigned long data) slot = ath9k_beacon_choose_slot(sc); vif = sc->beacon.bslot[slot]; + /* EDMA devices check that in the tx completion function. */ + if (!edma) { + if (ath9k_is_chanctx_enabled()) { + ath_chanctx_beacon_sent_ev(sc, + ATH_CHANCTX_EVENT_BEACON_SENT); + } + + if (ath9k_csa_is_finished(sc, vif)) + return; + } + if (!vif || !vif->bss_conf.enable_beacon) return; + if (ath9k_is_chanctx_enabled()) { + ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE); + } + bf = ath9k_beacon_generate(sc->hw, vif); if (sc->beacon.bmisscnt != 0) { @@ -394,20 +511,28 @@ void ath9k_beacon_tasklet(unsigned long data) * Both nexttbtt and intval have to be in usecs. */ static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, - u32 intval, bool reset_tsf) + u32 intval) { struct ath_hw *ah = sc->sc_ah; ath9k_hw_disable_interrupts(ah); - if (reset_tsf) - ath9k_hw_reset_tsf(ah); ath9k_beaconq_config(sc); ath9k_hw_beaconinit(ah, nexttbtt, intval); + ah->imask |= ATH9K_INT_SWBA; sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(ah); ath9k_hw_enable_interrupts(ah); } +static void ath9k_beacon_stop(struct ath_softc *sc) +{ + ath9k_hw_disable_interrupts(sc->sc_ah); + sc->sc_ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + sc->beacon.bmisscnt = 0; + ath9k_hw_set_interrupts(sc->sc_ah); + ath9k_hw_enable_interrupts(sc->sc_ah); +} + /* * For multi-bss ap support beacons are either staggered evenly over N slots or * burst together. For the former arrange for the SWBA to be delivered for each @@ -417,146 +542,18 @@ static void ath9k_beacon_config_ap(struct ath_softc *sc, struct ath_beacon_config *conf) { struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u32 nexttbtt, intval; - - /* NB: the beacon interval is kept internally in TU's */ - intval = TU_TO_USEC(conf->beacon_interval); - intval /= ATH_BCBUF; - nexttbtt = intval; - - if (conf->enable_beacon) - ah->imask |= ATH9K_INT_SWBA; - else - ah->imask &= ~ATH9K_INT_SWBA; - ath_dbg(common, BEACON, - "AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n", - (conf->enable_beacon) ? "Enable" : "Disable", - nexttbtt, intval, conf->beacon_interval); - - ath9k_beacon_init(sc, nexttbtt, intval, true); + ath9k_cmn_beacon_config_ap(ah, conf, ATH_BCBUF); + ath9k_beacon_init(sc, conf->nexttbtt, conf->intval); } -/* - * 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 ath9k_beacon_config_sta(struct ath_softc *sc, +static void ath9k_beacon_config_sta(struct ath_hw *ah, struct ath_beacon_config *conf) { - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_beacon_state bs; - int dtimperiod, dtimcount, sleepduration; - int cfpperiod, cfpcount; - u32 nexttbtt = 0, intval, tsftu; - u64 tsf; - int num_beacons, offset, dtim_dec_count, cfp_dec_count; - /* No need to configure beacon if we are not associated */ - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { - ath_dbg(common, BEACON, - "STA is not yet associated..skipping beacon config\n"); + if (ath9k_cmn_beacon_config_sta(ah, conf, &bs) == -EPERM) return; - } - - memset(&bs, 0, sizeof(bs)); - intval = conf->beacon_interval; - - /* - * Setup dtim and cfp parameters according to - * last beacon we received (which may be none). - */ - dtimperiod = conf->dtim_period; - dtimcount = conf->dtim_count; - if (dtimcount >= dtimperiod) /* NB: sanity check */ - dtimcount = 0; - cfpperiod = 1; /* NB: no PCF support yet */ - cfpcount = 0; - - sleepduration = conf->listen_interval * intval; - - /* - * Pull nexttbtt forward to reflect the current - * TSF and calculate dtim+cfp state for the result. - */ - tsf = ath9k_hw_gettsf64(ah); - tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; - - num_beacons = tsftu / intval + 1; - offset = tsftu % intval; - nexttbtt = tsftu - offset; - if (offset) - nexttbtt += intval; - - /* DTIM Beacon every dtimperiod Beacon */ - dtim_dec_count = num_beacons % dtimperiod; - /* CFP every cfpperiod DTIM Beacon */ - cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod; - if (dtim_dec_count) - cfp_dec_count++; - - dtimcount -= dtim_dec_count; - if (dtimcount < 0) - dtimcount += dtimperiod; - - cfpcount -= cfp_dec_count; - if (cfpcount < 0) - cfpcount += cfpperiod; - - 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; - - /* - * Calculate the number of consecutive beacons to miss* before taking - * a BMISS interrupt. The configuration is specified in TU so we only - * need calculate based on the beacon interval. Note that we clamp the - * result to at most 15 beacons. - */ - if (sleepduration > intval) { - bs.bs_bmissthreshold = conf->listen_interval * - ATH_DEFAULT_BMISS_LIMIT / 2; - } else { - bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval); - if (bs.bs_bmissthreshold > 15) - bs.bs_bmissthreshold = 15; - else if (bs.bs_bmissthreshold <= 0) - bs.bs_bmissthreshold = 1; - } - - /* - * Calculate sleep duration. The configuration is given in ms. - * We ensure 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), sleepduration); - if (bs.bs_sleepduration > bs.bs_dtimperiod) - bs.bs_sleepduration = bs.bs_dtimperiod; - - /* TSF out of range threshold fixed at 1 second */ - bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - - ath_dbg(common, BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); - ath_dbg(common, BEACON, - "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", - bs.bs_bmissthreshold, bs.bs_sleepduration, - bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); - - /* Set the computed STA beacon timers */ ath9k_hw_disable_interrupts(ah); ath9k_hw_set_sta_beacon_timers(ah, &bs); @@ -571,95 +568,36 @@ static void ath9k_beacon_config_adhoc(struct ath_softc *sc, { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - u32 intval, nexttbtt; ath9k_reset_beacon_status(sc); - intval = TU_TO_USEC(conf->beacon_interval); - - if (conf->ibss_creator) { - nexttbtt = intval; - } else { - u32 tbtt, offset, tsftu; - u64 tsf; - - /* - * Pull nexttbtt forward to reflect the current - * sync'd TSF. - */ - tsf = ath9k_hw_gettsf64(ah); - tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; - offset = tsftu % conf->beacon_interval; - tbtt = tsftu - offset; - if (offset) - tbtt += conf->beacon_interval; - - nexttbtt = TU_TO_USEC(tbtt); - } - - if (conf->enable_beacon) - ah->imask |= ATH9K_INT_SWBA; - else - ah->imask &= ~ATH9K_INT_SWBA; - - ath_dbg(common, BEACON, - "IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n", - (conf->enable_beacon) ? "Enable" : "Disable", - nexttbtt, intval, conf->beacon_interval); + ath9k_cmn_beacon_config_adhoc(ah, conf); - ath9k_beacon_init(sc, nexttbtt, intval, conf->ibss_creator); + ath9k_beacon_init(sc, conf->nexttbtt, conf->intval); /* * Set the global 'beacon has been configured' flag for the * joiner case in IBSS mode. */ if (!conf->ibss_creator && conf->enable_beacon) - set_bit(SC_OP_BEACONS, &sc->sc_flags); -} - -bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_vif *avp = (void *)vif->drv_priv; - - if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { - if ((vif->type != NL80211_IFTYPE_AP) || - (sc->nbcnvifs > 1)) { - ath_dbg(common, CONFIG, - "An AP interface is already present !\n"); - return false; - } - } - - if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { - if ((vif->type == NL80211_IFTYPE_STATION) && - test_bit(SC_OP_BEACONS, &sc->sc_flags) && - !avp->primary_sta_vif) { - ath_dbg(common, CONFIG, - "Beacon already configured for a station interface\n"); - return false; - } - } - - return true; + set_bit(ATH_OP_BEACONS, &common->op_flags); } static void ath9k_cache_beacon_config(struct ath_softc *sc, - struct ieee80211_bss_conf *bss_conf) + struct ath_chanctx *ctx, + struct ieee80211_vif *vif) { + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &ctx->beacon; ath_dbg(common, BEACON, "Caching beacon data for BSS: %pM\n", bss_conf->bssid); cur_conf->beacon_interval = bss_conf->beacon_int; cur_conf->dtim_period = bss_conf->dtim_period; - cur_conf->listen_interval = 1; cur_conf->dtim_count = 1; - cur_conf->ibss_creator = bss_conf->ibss_creator; - cur_conf->bmiss_timeout = - ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; + cur_conf->ibss_creator = vif->cfg.ibss_creator; /* * It looks like mac80211 may end up using beacon interval of zero in @@ -670,6 +608,9 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, if (cur_conf->beacon_interval == 0) cur_conf->beacon_interval = 100; + cur_conf->bmiss_timeout = + ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; + /* * We don't parse dtim period from mac80211 during the driver * initialization as it breaks association with hidden-ssid @@ -678,73 +619,86 @@ static void ath9k_cache_beacon_config(struct ath_softc *sc, if (cur_conf->dtim_period == 0) cur_conf->dtim_period = 1; + ath9k_set_tsfadjust(sc, cur_conf); } -void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, - u32 changed) +void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *main_vif, + bool beacons) { - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_vif *avp; + struct ath_chanctx *ctx; + struct ath_beacon_config *cur_conf; unsigned long flags; + bool enabled; bool skip_beacon = false; + if (!beacons) { + clear_bit(ATH_OP_BEACONS, &common->op_flags); + ath9k_beacon_stop(sc); + return; + } + + if (WARN_ON(!main_vif)) + return; + + avp = (void *)main_vif->drv_priv; + ctx = avp->chanctx; + cur_conf = &ctx->beacon; + enabled = cur_conf->enable_beacon; + cur_conf->enable_beacon = beacons; + if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { - ath9k_cache_beacon_config(sc, bss_conf); + ath9k_cache_beacon_config(sc, ctx, main_vif); + ath9k_set_beacon(sc); - set_bit(SC_OP_BEACONS, &sc->sc_flags); + set_bit(ATH_OP_BEACONS, &common->op_flags); return; - } - /* - * Take care of multiple interfaces when - * enabling/disabling SWBA. - */ - if (changed & BSS_CHANGED_BEACON_ENABLED) { - if (!bss_conf->enable_beacon && - (sc->nbcnvifs <= 1)) { - cur_conf->enable_beacon = false; - } else if (bss_conf->enable_beacon) { - cur_conf->enable_beacon = true; - ath9k_cache_beacon_config(sc, bss_conf); - } - } + /* Update the beacon configuration. */ + ath9k_cache_beacon_config(sc, ctx, main_vif); /* * Configure the HW beacon registers only when we have a valid * beacon interval. */ if (cur_conf->beacon_interval) { - /* - * If we are joining an existing IBSS network, start beaconing - * only after a TSF-sync has taken place. Ensure that this - * happens by setting the appropriate flags. + /* Special case to sync the TSF when joining an existing IBSS. + * This is only done if no AP interface is active. + * Note that mac80211 always resets the TSF when creating a new + * IBSS interface. */ - if ((changed & BSS_CHANGED_IBSS) && !bss_conf->ibss_creator && - bss_conf->enable_beacon) { + if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC && + !enabled && beacons && !main_vif->cfg.ibss_creator) { spin_lock_irqsave(&sc->sc_pm_lock, flags); sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; spin_unlock_irqrestore(&sc->sc_pm_lock, flags); skip_beacon = true; - } else { - ath9k_set_beacon(sc); } /* - * Do not set the SC_OP_BEACONS flag for IBSS joiner mode + * Do not set the ATH_OP_BEACONS flag for IBSS joiner mode * here, it is done in ath9k_beacon_config_adhoc(). */ - if (cur_conf->enable_beacon && !skip_beacon) - set_bit(SC_OP_BEACONS, &sc->sc_flags); - else - clear_bit(SC_OP_BEACONS, &sc->sc_flags); + if (beacons && !skip_beacon) { + set_bit(ATH_OP_BEACONS, &common->op_flags); + ath9k_set_beacon(sc); + } else { + clear_bit(ATH_OP_BEACONS, &common->op_flags); + ath9k_beacon_stop(sc); + } + } else { + clear_bit(ATH_OP_BEACONS, &common->op_flags); + ath9k_beacon_stop(sc); } } void ath9k_set_beacon(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; switch (sc->sc_ah->opmode) { case NL80211_IFTYPE_AP: @@ -755,7 +709,7 @@ void ath9k_set_beacon(struct ath_softc *sc) ath9k_beacon_config_adhoc(sc, cur_conf); break; case NL80211_IFTYPE_STATION: - ath9k_beacon_config_sta(sc, cur_conf); + ath9k_beacon_config_sta(sc->sc_ah, cur_conf); break; default: ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 9963b0bf9f72..ad3a3fda1b9c 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -15,6 +15,7 @@ */ #include <linux/export.h> +#include <linux/types.h> #include "hw.h" enum ath_bt_mode { @@ -34,6 +35,8 @@ struct ath_btcoex_config { u8 bt_priority_time; u8 bt_first_slot_time; bool bt_hold_rx_clear; + u8 wl_active_time; + u8 wl_qc_time; }; static const u32 ar9003_wlan_weights[ATH_BTCOEX_STOMP_MAX] @@ -65,37 +68,62 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) .bt_priority_time = 2, .bt_first_slot_time = 5, .bt_hold_rx_clear = true, + .wl_active_time = 0x20, + .wl_qc_time = 0x20, }; - u32 i, idx; bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity; + u8 time_extend = ath_bt_config.bt_time_extend; + u8 first_slot_time = ath_bt_config.bt_first_slot_time; if (AR_SREV_9300_20_OR_LATER(ah)) rxclear_polarity = !ath_bt_config.bt_rxclear_polarity; + if (AR_SREV_SOC(ah)) { + first_slot_time = 0x1d; + time_extend = 0xa; + + btcoex_hw->bt_coex_mode3 = + SM(ath_bt_config.wl_active_time, AR_BT_WL_ACTIVE_TIME) | + SM(ath_bt_config.wl_qc_time, AR_BT_WL_QC_TIME); + + btcoex_hw->bt_coex_mode2 = + AR_BT_PROTECT_BT_AFTER_WAKEUP | + AR_BT_PHY_ERR_BT_COLL_ENABLE; + } + btcoex_hw->bt_coex_mode = (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) | - SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) | + SM(time_extend, AR_BT_TIME_EXTEND) | SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) | SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | SM(ath_bt_config.bt_mode, AR_BT_MODE) | SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) | SM(rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) | - SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) | + SM(first_slot_time, AR_BT_FIRST_SLOT_TIME) | SM(qnum, AR_BT_QCU_THRESH); - btcoex_hw->bt_coex_mode2 = + btcoex_hw->bt_coex_mode2 |= SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) | SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) | AR_BT_DISABLE_BT_ANT; - - for (i = 0; i < 32; i++) { - idx = (debruijn32 << i) >> 27; - ah->hw_gen_timers.gen_timer_index[idx] = i; - } } EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw); +static void ath9k_hw_btcoex_pin_init(struct ath_hw *ah, u8 wlanactive_gpio, + u8 btactive_gpio, u8 btpriority_gpio) +{ + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; + + if (btcoex_hw->scheme != ATH_BTCOEX_CFG_2WIRE && + btcoex_hw->scheme != ATH_BTCOEX_CFG_3WIRE) + return; + + btcoex_hw->btactive_gpio = btactive_gpio; + btcoex_hw->wlanactive_gpio = wlanactive_gpio; + btcoex_hw->btpriority_gpio = btpriority_gpio; +} + void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -109,21 +137,23 @@ void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah) return; } - if (AR_SREV_9300_20_OR_LATER(ah)) { + if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) { + btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI; + } else if (AR_SREV_9300_20_OR_LATER(ah)) { btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; - btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300; - btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300; - btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300; - } else if (AR_SREV_9280_20_OR_LATER(ah)) { - btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280; - btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280; - if (AR_SREV_9285(ah)) { + ath9k_hw_btcoex_pin_init(ah, ATH_WLANACTIVE_GPIO_9300, + ATH_BTACTIVE_GPIO_9300, + ATH_BTPRIORITY_GPIO_9300); + } else if (AR_SREV_9280_20_OR_LATER(ah)) { + if (AR_SREV_9285(ah)) btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; - btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9285; - } else { + else btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE; - } + + ath9k_hw_btcoex_pin_init(ah, ATH_WLANACTIVE_GPIO_9280, + ATH_BTACTIVE_GPIO_9280, + ATH_BTPRIORITY_GPIO_9285); } } EXPORT_SYMBOL(ath9k_hw_btcoex_init_scheme); @@ -133,20 +163,22 @@ void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; /* connect bt_active to baseband */ - REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, + REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL(ah), (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL(ah), AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); /* Set input mux for bt_active to gpio pin */ - REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, - AR_GPIO_INPUT_MUX1_BT_ACTIVE, - btcoex_hw->btactive_gpio); + if (!AR_SREV_SOC(ah)) + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1(ah), + AR_GPIO_INPUT_MUX1_BT_ACTIVE, + btcoex_hw->btactive_gpio); /* Configure the desired gpio port for input */ - ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio); + ath9k_hw_gpio_request_in(ah, btcoex_hw->btactive_gpio, + "ath9k-btactive"); } EXPORT_SYMBOL(ath9k_hw_btcoex_init_2wire); @@ -155,27 +187,39 @@ void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; /* btcoex 3-wire */ - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL(ah), (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB | AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB)); /* Set input mux for bt_prority_async and * bt_active_async to GPIO pins */ - REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, - AR_GPIO_INPUT_MUX1_BT_ACTIVE, - btcoex_hw->btactive_gpio); - - REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, - AR_GPIO_INPUT_MUX1_BT_PRIORITY, - btcoex_hw->btpriority_gpio); + if (!AR_SREV_SOC(ah)) { + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1(ah), + AR_GPIO_INPUT_MUX1_BT_ACTIVE, + btcoex_hw->btactive_gpio); + REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1(ah), + AR_GPIO_INPUT_MUX1_BT_PRIORITY, + btcoex_hw->btpriority_gpio); + } /* Configure the desired GPIO ports for input */ - - ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio); - ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btpriority_gpio); + ath9k_hw_gpio_request_in(ah, btcoex_hw->btactive_gpio, + "ath9k-btactive"); + ath9k_hw_gpio_request_in(ah, btcoex_hw->btpriority_gpio, + "ath9k-btpriority"); } EXPORT_SYMBOL(ath9k_hw_btcoex_init_3wire); +void ath9k_hw_btcoex_deinit(struct ath_hw *ah) +{ + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; + + ath9k_hw_gpio_free(ah, btcoex_hw->btactive_gpio); + ath9k_hw_gpio_free(ah, btcoex_hw->btpriority_gpio); + ath9k_hw_gpio_free(ah, btcoex_hw->wlanactive_gpio); +} +EXPORT_SYMBOL(ath9k_hw_btcoex_deinit); + void ath9k_hw_btcoex_init_mci(struct ath_hw *ah) { ah->btcoex_hw.mci.ready = false; @@ -205,8 +249,9 @@ static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah) struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; /* Configure the desired GPIO port for TX_FRAME output */ - ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio, - AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); + ath9k_hw_gpio_request_out(ah, btcoex_hw->wlanactive_gpio, + "ath9k-wlanactive", + AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); } /* @@ -251,13 +296,13 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, txprio_shift[i-1]); } } + /* Last WLAN weight has to be adjusted wrt tx priority */ if (concur_tx) { btcoex_hw->wlan_weight[i-1] &= ~(0xff << txprio_shift[i-1]); btcoex_hw->wlan_weight[i-1] |= (btcoex_hw->tx_prio[stomp_type] << txprio_shift[i-1]); } - } EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); @@ -272,9 +317,14 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) * Program coex mode and weight registers to * enable coex 3-wire */ + if (AR_SREV_SOC(ah)) + REG_CLR_BIT(ah, AR_BT_COEX_MODE2, AR_BT_PHY_ERR_BT_COLL_ENABLE); + REG_WRITE(ah, AR_BT_COEX_MODE, btcoex->bt_coex_mode); REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex->bt_coex_mode2); + if (AR_SREV_SOC(ah)) + REG_WRITE(ah, AR_BT_COEX_MODE3, btcoex->bt_coex_mode3); if (AR_SREV_9300_20_OR_LATER(ah)) { REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, btcoex->wlan_weight[0]); @@ -285,8 +335,6 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) } else REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex->bt_coex_weights); - - if (AR_SREV_9271(ah)) { val = REG_READ(ah, 0x50040); val &= 0xFFFFFEFF; @@ -296,8 +344,9 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); - ath9k_hw_cfg_output(ah, btcoex->wlanactive_gpio, - AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL); + ath9k_hw_gpio_request_out(ah, btcoex->wlanactive_gpio, + "ath9k-wlanactive", + AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL); } static void ath9k_hw_btcoex_enable_mci(struct ath_hw *ah) @@ -313,6 +362,18 @@ static void ath9k_hw_btcoex_enable_mci(struct ath_hw *ah) btcoex->enabled = true; } +static void ath9k_hw_btcoex_disable_mci(struct ath_hw *ah) +{ + struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; + int i; + + ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); + + for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) + REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i), + btcoex_hw->wlan_weight[i]); +} + void ath9k_hw_btcoex_enable(struct ath_hw *ah) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; @@ -324,17 +385,19 @@ void ath9k_hw_btcoex_enable(struct ath_hw *ah) ath9k_hw_btcoex_enable_2wire(ah); break; case ATH_BTCOEX_CFG_3WIRE: - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { - ath9k_hw_btcoex_enable_mci(ah); - return; - } ath9k_hw_btcoex_enable_3wire(ah); break; + case ATH_BTCOEX_CFG_MCI: + ath9k_hw_btcoex_enable_mci(ah); + break; } - REG_RMW(ah, AR_GPIO_PDPU, - (0x2 << (btcoex_hw->btactive_gpio * 2)), - (0x3 << (btcoex_hw->btactive_gpio * 2))); + if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_MCI && + !AR_SREV_SOC(ah)) { + REG_RMW(ah, AR_GPIO_PDPU(ah), + (0x2 << (btcoex_hw->btactive_gpio * 2)), + (0x3 << (btcoex_hw->btactive_gpio * 2))); + } ah->btcoex_hw.enabled = true; } @@ -346,17 +409,17 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) int i; btcoex_hw->enabled = false; - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { - ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); - for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) - REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i), - btcoex_hw->wlan_weight[i]); + + if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_MCI) { + ath9k_hw_btcoex_disable_mci(ah); return; } - ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0); - ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio, - AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + if (!AR_SREV_9300_20_OR_LATER(ah)) + ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0); + + ath9k_hw_gpio_request_out(ah, btcoex_hw->wlanactive_gpio, + NULL, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) { REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 6de26ea5d5fa..1bdfa8465b92 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -44,6 +44,9 @@ #define AR9300_NUM_BT_WEIGHTS 4 #define AR9300_NUM_WLAN_WEIGHTS 4 + +#define ATH_AIC_MAX_BT_CHANNEL 79 + /* Defines the BT AR_BT_COEX_WGHT used */ enum ath_stomp_type { ATH_BTCOEX_STOMP_ALL, @@ -58,6 +61,7 @@ enum ath_btcoex_scheme { ATH_BTCOEX_CFG_NONE, ATH_BTCOEX_CFG_2WIRE, ATH_BTCOEX_CFG_3WIRE, + ATH_BTCOEX_CFG_MCI, }; struct ath9k_hw_mci { @@ -92,9 +96,18 @@ struct ath9k_hw_mci { u32 last_recovery; }; +struct ath9k_hw_aic { + bool aic_enabled; + u8 aic_cal_state; + u8 aic_caled_chan; + u32 aic_sram[ATH_AIC_MAX_BT_CHANNEL]; + u32 aic_cal_start_time; +}; + struct ath_btcoex_hw { enum ath_btcoex_scheme scheme; struct ath9k_hw_mci mci; + struct ath9k_hw_aic aic; bool enabled; u8 wlanactive_gpio; u8 btactive_gpio; @@ -102,6 +115,7 @@ struct ath_btcoex_hw { u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */ u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */ u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */ + u32 bt_coex_mode3; /* Register setting for AR_BT_COEX_MODE3 */ u32 bt_weight[AR9300_NUM_BT_WEIGHTS]; u32 wlan_weight[AR9300_NUM_WLAN_WEIGHTS]; u8 tx_prio[ATH_BTCOEX_STOMP_MAX]; @@ -110,6 +124,7 @@ struct ath_btcoex_hw { void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah); void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah); void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah); +void ath9k_hw_btcoex_deinit(struct ath_hw *ah); void ath9k_hw_btcoex_init_mci(struct ath_hw *ah); void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum); void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 5e8219a91e25..b4ab85bd7895 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -16,32 +16,25 @@ #include "hw.h" #include "hw-ops.h" +#include <linux/sort.h> #include <linux/export.h> /* Common calibration code */ +static int rcmp_i16(const void *x, const void *y) +{ + /* Sort in reverse order. */ + return *(int16_t *)y - *(int16_t *)x; +} static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) { - int16_t nfval; - int16_t sort[ATH9K_NF_CAL_HIST_MAX]; - int i, j; - - for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) - sort[i] = nfCalBuffer[i]; - - for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { - for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { - if (sort[j] > sort[j - 1]) { - nfval = sort[j]; - sort[j] = sort[j - 1]; - sort[j - 1] = nfval; - } - } - } - nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; + int16_t nfcal[ATH9K_NF_CAL_HIST_MAX]; + + memcpy(nfcal, nfCalBuffer, sizeof(nfcal)); + sort(nfcal, ATH9K_NF_CAL_HIST_MAX, sizeof(int16_t), rcmp_i16, NULL); - return nfval; + return nfcal[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; } static struct ath_nf_limits *ath9k_hw_get_nf_limits(struct ath_hw *ah, @@ -58,19 +51,25 @@ static struct ath_nf_limits *ath9k_hw_get_nf_limits(struct ath_hw *ah, } static s16 ath9k_hw_get_default_nf(struct ath_hw *ah, - struct ath9k_channel *chan) + struct ath9k_channel *chan, + int chain) { - return ath9k_hw_get_nf_limits(ah, chan)->nominal; + s16 calib_nf = ath9k_hw_get_nf_limits(ah, chan)->cal[chain]; + + if (calib_nf) + return calib_nf; + else + return ath9k_hw_get_nf_limits(ah, chan)->nominal; } -s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) +s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan, + s16 nf) { s8 noise = ATH_DEFAULT_NOISE_FLOOR; - if (chan && chan->noisefloor) { - s8 delta = chan->noisefloor - - ATH9K_NF_CAL_NOISE_THRESH - - ath9k_hw_get_default_nf(ah, chan); + if (nf) { + s8 delta = nf - ATH9K_NF_CAL_NOISE_THRESH - + ath9k_hw_get_default_nf(ah, chan, 0); if (delta > 0) noise += delta; } @@ -119,7 +118,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, ath_dbg(common, CALIBRATE, "NFmid[%d] (%d) > MAX (%d), %s\n", i, h[i].privNF, limit->max, - (cal->nfcal_interference ? + (test_bit(NFCAL_INTF, &cal->cal_flags) ? "not corrected (due to interference)" : "correcting to MAX")); @@ -130,7 +129,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, * we bypass this limit here in order to better deal * with our environment. */ - if (!cal->nfcal_interference) + if (!test_bit(NFCAL_INTF, &cal->cal_flags)) h[i].privNF = limit->max; } } @@ -141,18 +140,18 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, * Re-enable the enforcement of the NF maximum again. */ if (!high_nf_mid) - cal->nfcal_interference = false; + clear_bit(NFCAL_INTF, &cal->cal_flags); } static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah, - enum ieee80211_band band, + enum nl80211_band band, int16_t *nft) { switch (band) { - case IEEE80211_BAND_5GHZ: + case NL80211_BAND_5GHZ: *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5); break; - case IEEE80211_BAND_2GHZ: + case NL80211_BAND_2GHZ: *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2); break; default: @@ -170,6 +169,7 @@ void ath9k_hw_reset_calibration(struct ath_hw *ah, ath9k_hw_setup_calibration(ah, currCal); + ah->cal_start_time = jiffies; currCal->calState = CAL_RUNNING; for (i = 0; i < AR5416_MAX_CHAINS; i++) { @@ -186,7 +186,6 @@ void ath9k_hw_reset_calibration(struct ath_hw *ah, bool ath9k_hw_reset_calvalid(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_conf *conf = &common->hw->conf; struct ath9k_cal_list *currCal = ah->cal_list_curr; if (!ah->caldata) @@ -204,14 +203,17 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah) return true; } - if (!(ah->supp_cals & currCal->calData->calType)) - return true; + currCal = ah->cal_list; + do { + ath_dbg(common, CALIBRATE, "Resetting Cal %d state for channel %u\n", + currCal->calData->calType, + ah->curchan->chan->center_freq); - ath_dbg(common, CALIBRATE, "Resetting Cal %d state for channel %u\n", - currCal->calData->calType, conf->chandef.chan->center_freq); + ah->caldata->CalValid &= ~currCal->calData->calType; + currCal->calState = CAL_WAITING; - ah->caldata->CalValid &= ~currCal->calData->calType; - currCal->calState = CAL_WAITING; + currCal = currCal->calNext; + } while (currCal != ah->cal_list); return false; } @@ -220,77 +222,108 @@ EXPORT_SYMBOL(ath9k_hw_reset_calvalid); void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update) { if (ah->caldata) - ah->caldata->nfcal_pending = true; + set_bit(NFCAL_PENDING, &ah->caldata->cal_flags); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_ENABLE_NF); if (update) - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_NO_UPDATE_NF); else - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_NO_UPDATE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_NF); } -void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) +int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath9k_nfcal_hist *h = NULL; unsigned i, j; - int32_t val; u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_conf *conf = &common->hw->conf; - s16 default_nf = ath9k_hw_get_default_nf(ah, chan); + s16 default_nf = ath9k_hw_get_nf_limits(ah, chan)->nominal; + u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL(ah)); if (ah->caldata) h = ah->caldata->nfCalHist; + ENABLE_REG_RMW_BUFFER(ah); for (i = 0; i < NUM_NF_READINGS; i++) { if (chainmask & (1 << i)) { s16 nfval; - if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)) + if ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(chan)) continue; - if (h) + if (ah->nf_override) + nfval = ah->nf_override; + else if (h) nfval = h[i].privNF; - else - nfval = default_nf; + else { + /* Try to get calibrated noise floor value */ + nfval = + ath9k_hw_get_nf_limits(ah, chan)->cal[i]; + if (nfval > -60 || nfval < -127) + nfval = default_nf; + } - val = REG_READ(ah, ah->nf_regs[i]); - val &= 0xFFFFFE00; - val |= (((u32) nfval << 1) & 0x1ff); - REG_WRITE(ah, ah->nf_regs[i], val); + REG_RMW(ah, ah->nf_regs[i], + (((u32) nfval << 1) & 0x1ff), 0x1ff); } } /* + * stop NF cal if ongoing to ensure NF load completes immediately + * (or after end rx/tx frame if ongoing) + */ + if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) { + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_NF); + REG_RMW_BUFFER_FLUSH(ah); + ENABLE_REG_RMW_BUFFER(ah); + } + + /* * Load software filtered NF value into baseband internal minCCApwr * variable. */ - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_ENABLE_NF); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_NO_UPDATE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_NF); + REG_RMW_BUFFER_FLUSH(ah); /* * Wait for load to complete, should be fast, a few 10s of us. - * The max delay was changed from an original 250us to 10000us - * since 250us often results in NF load timeout and causes deaf - * condition during stress testing 12/12/2009 + * The max delay was changed from an original 250us to 22.2 msec. + * This would increase timeout to the longest possible frame + * (11n max length 22.1 msec) */ - for (j = 0; j < 10000; j++) { - if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & - AR_PHY_AGC_CONTROL_NF) == 0) + for (j = 0; j < 22200; j++) { + if ((REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) & + AR_PHY_AGC_CONTROL_NF) == 0) break; udelay(10); } /* + * Restart NF so it can continue. + */ + if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) { + ENABLE_REG_RMW_BUFFER(ah); + if (bb_agc_ctl & AR_PHY_AGC_CONTROL_ENABLE_NF) + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), + AR_PHY_AGC_CONTROL_ENABLE_NF); + if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NO_UPDATE_NF) + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), + AR_PHY_AGC_CONTROL_NO_UPDATE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_NF); + REG_RMW_BUFFER_FLUSH(ah); + } + + /* * We timed out waiting for the noisefloor to load, probably due to an * in-progress rx. Simply return here and allow the load plenty of time * to complete before the next calibration interval. We need to avoid @@ -299,11 +332,11 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) * here, the baseband nf cal will just be capped by our present * noisefloor until the next calibration timer. */ - if (j == 10000) { + if (j == 22200) { ath_dbg(common, ANY, "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n", - REG_READ(ah, AR_PHY_AGC_CONTROL)); - return; + REG_READ(ah, AR_PHY_AGC_CONTROL(ah))); + return -ETIMEDOUT; } /* @@ -311,20 +344,21 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) * by the median we just loaded. This will be initial (and max) value * of next noise floor calibration the baseband does. */ - ENABLE_REGWRITE_BUFFER(ah); + ENABLE_REG_RMW_BUFFER(ah); for (i = 0; i < NUM_NF_READINGS; i++) { if (chainmask & (1 << i)) { - if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)) + if ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(chan)) continue; - val = REG_READ(ah, ah->nf_regs[i]); - val &= 0xFFFFFE00; - val |= (((u32) (-50) << 1) & 0x1ff); - REG_WRITE(ah, ah->nf_regs[i], val); + REG_RMW(ah, ah->nf_regs[i], + (((u32) (-50) << 1) & 0x1ff), 0x1ff); } } - REGWRITE_BUFFER_FLUSH(ah); + REG_RMW_BUFFER_FLUSH(ah); + + return 0; } +EXPORT_SYMBOL(ath9k_hw_loadnf); static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf) @@ -369,7 +403,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) struct ieee80211_channel *c = chan->chan; struct ath9k_hw_cal_data *caldata = ah->caldata; - if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { + if (REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) & AR_PHY_AGC_CONTROL_NF) { ath_dbg(common, CALIBRATE, "NF did not complete in calibration window\n"); return false; @@ -391,10 +425,10 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) } h = caldata->nfCalHist; - caldata->nfcal_pending = false; + clear_bit(NFCAL_PENDING, &caldata->cal_flags); ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray); chan->noisefloor = h[0].privNF; - ah->noise = ath9k_hw_getchan_noise(ah, chan); + ah->noise = ath9k_hw_getchan_noise(ah, chan, chan->noisefloor); return true; } EXPORT_SYMBOL(ath9k_hw_getnf); @@ -403,21 +437,19 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath9k_nfcal_hist *h; - s16 default_nf; - int i, j; + int i, j, k = 0; ah->caldata->channel = chan->channel; ah->caldata->channelFlags = chan->channelFlags; - ah->caldata->chanmode = chan->chanmode; h = ah->caldata->nfCalHist; - default_nf = ath9k_hw_get_default_nf(ah, chan); for (i = 0; i < NUM_NF_READINGS; i++) { h[i].currIndex = 0; - h[i].privNF = default_nf; + h[i].privNF = ath9k_hw_get_default_nf(ah, chan, k); h[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH; - for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { - h[i].nfCalBuffer[j] = default_nf; - } + for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) + h[i].nfCalBuffer[j] = h[i].privNF; + if (++k >= AR5416_MAX_CHAINS) + k = 0; } } @@ -437,12 +469,12 @@ void ath9k_hw_bstuck_nfcal(struct ath_hw *ah) * the baseband update the internal NF value itself, similar to * what is being done after a full reset. */ - if (!caldata->nfcal_pending) + if (!test_bit(NFCAL_PENDING, &caldata->cal_flags)) ath9k_hw_start_nfcal(ah, true); - else if (!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF)) + else if (!(REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) & AR_PHY_AGC_CONTROL_NF)) ath9k_hw_getnf(ah, ah->curchan); - caldata->nfcal_interference = true; + set_bit(NFCAL_INTF, &caldata->cal_flags); } EXPORT_SYMBOL(ath9k_hw_bstuck_nfcal); diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 3d70b8c2bcdd..87badf4bb8a4 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -109,14 +109,15 @@ struct ath9k_pacal_info{ bool ath9k_hw_reset_calvalid(struct ath_hw *ah); void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update); -void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan); +int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan); bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_hw_bstuck_nfcal(struct ath_hw *ah); void ath9k_hw_reset_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal); -s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); +s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan, + s16 nf); #endif /* CALIB_H */ diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c new file mode 100644 index 000000000000..121e51ce1bc0 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -0,0 +1,1646 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +/* Set/change channels. If the channel is really being changed, it's done + * by resetting the chip. To accomplish this we must first cleanup any pending + * DMA, then restart stuff. + */ +static int ath_set_channel(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_hw *hw = sc->hw; + struct ath9k_channel *hchan; + struct cfg80211_chan_def *chandef = &sc->cur_chan->chandef; + struct ieee80211_channel *chan = chandef->chan; + int pos = chan->hw_value; + unsigned long flags; + int old_pos = -1; + int r; + + if (test_bit(ATH_OP_INVALID, &common->op_flags)) + return -EIO; + + if (ah->curchan) + old_pos = ah->curchan - &ah->channels[0]; + + ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", + chan->center_freq, chandef->width); + + /* update survey stats for the old channel before switching */ + spin_lock_irqsave(&common->cc_lock, flags); + ath_update_survey_stats(sc); + spin_unlock_irqrestore(&common->cc_lock, flags); + + ath9k_cmn_get_channel(hw, ah, chandef); + + /* If the operating channel changes, change the survey in-use flags + * along with it. + * Reset the survey data for the new channel, unless we're switching + * back to the operating channel from an off-channel operation. + */ + if (!sc->cur_chan->offchannel && sc->cur_survey != &sc->survey[pos]) { + if (sc->cur_survey) + sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; + + sc->cur_survey = &sc->survey[pos]; + + memset(sc->cur_survey, 0, sizeof(struct survey_info)); + sc->cur_survey->filled |= SURVEY_INFO_IN_USE; + } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { + memset(&sc->survey[pos], 0, sizeof(struct survey_info)); + } + + hchan = &sc->sc_ah->channels[pos]; + r = ath_reset(sc, hchan); + if (r) + return r; + + /* The most recent snapshot of channel->noisefloor for the old + * channel is only available after the hardware reset. Copy it to + * the survey stats now. + */ + if (old_pos >= 0) + ath_update_survey_nf(sc, old_pos); + + /* Enable radar pulse detection if on a DFS channel. Spectral + * scanning and radar detection can not be used concurrently. + */ + if (hw->conf.radar_enabled) { + u32 rxfilter; + + rxfilter = ath9k_hw_getrxfilter(ah); + rxfilter |= ATH9K_RX_FILTER_PHYRADAR | + ATH9K_RX_FILTER_PHYERR; + ath9k_hw_setrxfilter(ah, rxfilter); + ath_dbg(common, DFS, "DFS enabled at freq %d\n", + chan->center_freq); + } else { + /* perform spectral scan if requested. */ + if (test_bit(ATH_OP_SCANNING, &common->op_flags) && + sc->spec_priv.spectral_mode == SPECTRAL_CHANSCAN) + ath9k_cmn_spectral_scan_trigger(common, &sc->spec_priv); + } + + return 0; +} + +void ath_chanctx_init(struct ath_softc *sc) +{ + struct ath_chanctx *ctx; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + int i, j; + + sband = &common->sbands[NL80211_BAND_2GHZ]; + if (!sband->n_channels) + sband = &common->sbands[NL80211_BAND_5GHZ]; + + chan = &sband->channels[0]; + for (i = 0; i < ATH9K_NUM_CHANCTX; i++) { + ctx = &sc->chanctx[i]; + cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20); + INIT_LIST_HEAD(&ctx->vifs); + ctx->txpower = ATH_TXPOWER_MAX; + ctx->flush_timeout = HZ / 5; /* 200ms */ + for (j = 0; j < ARRAY_SIZE(ctx->acq); j++) { + INIT_LIST_HEAD(&ctx->acq[j].acq_new); + INIT_LIST_HEAD(&ctx->acq[j].acq_old); + spin_lock_init(&ctx->acq[j].lock); + } + } +} + +void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, + struct cfg80211_chan_def *chandef) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + bool cur_chan; + + spin_lock_bh(&sc->chan_lock); + if (chandef) + memcpy(&ctx->chandef, chandef, sizeof(*chandef)); + cur_chan = sc->cur_chan == ctx; + spin_unlock_bh(&sc->chan_lock); + + if (!cur_chan) { + ath_dbg(common, CHAN_CTX, + "Current context differs from the new context\n"); + return; + } + + ath_set_channel(sc); +} + +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + +/*************/ +/* Utilities */ +/*************/ + +struct ath_chanctx* ath_is_go_chanctx_present(struct ath_softc *sc) +{ + struct ath_chanctx *ctx; + struct ath_vif *avp; + struct ieee80211_vif *vif; + + spin_lock_bh(&sc->chan_lock); + + ath_for_each_chanctx(sc, ctx) { + if (!ctx->active) + continue; + + list_for_each_entry(avp, &ctx->vifs, list) { + vif = avp->vif; + + if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_P2P_GO) { + spin_unlock_bh(&sc->chan_lock); + return ctx; + } + } + } + + spin_unlock_bh(&sc->chan_lock); + return NULL; +} + +/**********************************************************/ +/* Functions to handle the channel context state machine. */ +/**********************************************************/ + +static const char *offchannel_state_string(enum ath_offchannel_state state) +{ + switch (state) { + case_rtn_string(ATH_OFFCHANNEL_IDLE); + case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND); + case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT); + case_rtn_string(ATH_OFFCHANNEL_SUSPEND); + case_rtn_string(ATH_OFFCHANNEL_ROC_START); + case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT); + case_rtn_string(ATH_OFFCHANNEL_ROC_DONE); + default: + return "unknown"; + } +} + +static const char *chanctx_event_string(enum ath_chanctx_event ev) +{ + switch (ev) { + case_rtn_string(ATH_CHANCTX_EVENT_BEACON_PREPARE); + case_rtn_string(ATH_CHANCTX_EVENT_BEACON_SENT); + case_rtn_string(ATH_CHANCTX_EVENT_TSF_TIMER); + case_rtn_string(ATH_CHANCTX_EVENT_BEACON_RECEIVED); + case_rtn_string(ATH_CHANCTX_EVENT_AUTHORIZED); + case_rtn_string(ATH_CHANCTX_EVENT_SWITCH); + case_rtn_string(ATH_CHANCTX_EVENT_ASSIGN); + case_rtn_string(ATH_CHANCTX_EVENT_UNASSIGN); + case_rtn_string(ATH_CHANCTX_EVENT_CHANGE); + case_rtn_string(ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL); + default: + return "unknown"; + } +} + +static const char *chanctx_state_string(enum ath_chanctx_state state) +{ + switch (state) { + case_rtn_string(ATH_CHANCTX_STATE_IDLE); + case_rtn_string(ATH_CHANCTX_STATE_WAIT_FOR_BEACON); + case_rtn_string(ATH_CHANCTX_STATE_WAIT_FOR_TIMER); + case_rtn_string(ATH_CHANCTX_STATE_SWITCH); + case_rtn_string(ATH_CHANCTX_STATE_FORCE_ACTIVE); + default: + return "unknown"; + } +} + +static u32 chanctx_event_delta(struct ath_softc *sc) +{ + ktime_t ts = ktime_get_raw(); + s64 ms = ktime_ms_delta(ts, sc->last_event_time); + + sc->last_event_time = ts; + return ms; +} + +void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_chanctx *ictx; + struct ath_vif *avp; + bool active = false; + u8 n_active = 0; + + if (!ctx) + return; + + if (ctx == &sc->offchannel.chan) { + spin_lock_bh(&sc->chan_lock); + + if (likely(sc->sched.channel_switch_time)) + ctx->flush_timeout = + usecs_to_jiffies(sc->sched.channel_switch_time); + else + ctx->flush_timeout = + msecs_to_jiffies(10); + + spin_unlock_bh(&sc->chan_lock); + + /* + * There is no need to iterate over the + * active/assigned channel contexts if + * the current context is offchannel. + */ + return; + } + + ictx = ctx; + + list_for_each_entry(avp, &ctx->vifs, list) { + struct ieee80211_vif *vif = avp->vif; + + switch (vif->type) { + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_STATION: + if (avp->assoc) + active = true; + break; + default: + active = true; + break; + } + } + ctx->active = active; + + ath_for_each_chanctx(sc, ctx) { + if (!ctx->assigned || list_empty(&ctx->vifs)) + continue; + n_active++; + } + + spin_lock_bh(&sc->chan_lock); + + if (n_active <= 1) { + ictx->flush_timeout = HZ / 5; + clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags); + spin_unlock_bh(&sc->chan_lock); + return; + } + + ictx->flush_timeout = usecs_to_jiffies(sc->sched.channel_switch_time); + + if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) { + spin_unlock_bh(&sc->chan_lock); + return; + } + + spin_unlock_bh(&sc->chan_lock); + + if (ath9k_is_chanctx_enabled()) { + ath_chanctx_event(sc, NULL, + ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL); + } +} + +static struct ath_chanctx * +ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx) +{ + int idx = ctx - &sc->chanctx[0]; + + return &sc->chanctx[!idx]; +} + +static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc) +{ + struct ath_chanctx *prev, *cur; + u32 cur_tsf, prev_tsf, beacon_int; + ktime_t ts; + s32 offset; + + beacon_int = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); + + cur = sc->cur_chan; + prev = ath_chanctx_get_next(sc, cur); + + if (!prev->switch_after_beacon) + return; + + ts = ktime_get_raw(); + cur_tsf = (u32) cur->tsf_val + + ath9k_hw_get_tsf_offset(cur->tsf_ts, ts); + + prev_tsf = prev->last_beacon - (u32) prev->tsf_val + cur_tsf; + prev_tsf -= ath9k_hw_get_tsf_offset(prev->tsf_ts, ts); + + /* Adjust the TSF time of the AP chanctx to keep its beacons + * at half beacon interval offset relative to the STA chanctx. + */ + offset = cur_tsf - prev_tsf; + + /* Ignore stale data or spurious timestamps */ + if (offset < 0 || offset > 3 * beacon_int) + return; + + offset = beacon_int / 2 - (offset % beacon_int); + prev->tsf_val += offset; +} + +/* Configure the TSF based hardware timer for a channel switch. + * Also set up backup software timer, in case the gen timer fails. + * This could be caused by a hardware reset. + */ +static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + unsigned long timeout; + + ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000); + tsf_time -= ath9k_hw_gettsf32(ah); + timeout = msecs_to_jiffies(tsf_time / 1000) + 1; + mod_timer(&sc->sched.timer, jiffies + timeout); + + ath_dbg(common, CHAN_CTX, + "Setup chanctx timer with timeout: %d (%d) ms\n", + tsf_time / 1000, jiffies_to_msecs(timeout)); +} + +static void ath_chanctx_handle_bmiss(struct ath_softc *sc, + struct ath_chanctx *ctx, + struct ath_vif *avp) +{ + /* + * Clear the extend_absence flag if it had been + * set during the previous beacon transmission, + * since we need to revert to the normal NoA + * schedule. + */ + if (ctx->active && sc->sched.extend_absence) { + avp->noa_duration = 0; + sc->sched.extend_absence = false; + } + + /* If at least two consecutive beacons were missed on the STA + * chanctx, stay on the STA channel for one extra beacon period, + * to resync the timer properly. + */ + if (ctx->active && sc->sched.beacon_miss >= 2) { + avp->noa_duration = 0; + sc->sched.extend_absence = true; + } +} + +static void ath_chanctx_offchannel_noa(struct ath_softc *sc, + struct ath_chanctx *ctx, + struct ath_vif *avp, + u32 tsf_time) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + avp->noa_index++; + avp->offchannel_start = tsf_time; + avp->offchannel_duration = sc->sched.offchannel_duration; + + ath_dbg(common, CHAN_CTX, + "offchannel noa_duration: %d, noa_start: %u, noa_index: %d\n", + avp->offchannel_duration, + avp->offchannel_start, + avp->noa_index); + + /* + * When multiple contexts are active, the NoA + * has to be recalculated and advertised after + * an offchannel operation. + */ + if (ctx->active && avp->noa_duration) + avp->noa_duration = 0; +} + +static void ath_chanctx_set_periodic_noa(struct ath_softc *sc, + struct ath_vif *avp, + struct ath_beacon_config *cur_conf, + u32 tsf_time, + u32 beacon_int) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + avp->noa_index++; + avp->noa_start = tsf_time; + + if (sc->sched.extend_absence) + avp->noa_duration = (3 * beacon_int / 2) + + sc->sched.channel_switch_time; + else + avp->noa_duration = + TU_TO_USEC(cur_conf->beacon_interval) / 2 + + sc->sched.channel_switch_time; + + if (test_bit(ATH_OP_SCANNING, &common->op_flags) || + sc->sched.extend_absence) + avp->periodic_noa = false; + else + avp->periodic_noa = true; + + ath_dbg(common, CHAN_CTX, + "noa_duration: %d, noa_start: %u, noa_index: %d, periodic: %d\n", + avp->noa_duration, + avp->noa_start, + avp->noa_index, + avp->periodic_noa); +} + +static void ath_chanctx_set_oneshot_noa(struct ath_softc *sc, + struct ath_vif *avp, + u32 tsf_time, + u32 duration) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + avp->noa_index++; + avp->noa_start = tsf_time; + avp->periodic_noa = false; + avp->oneshot_noa = true; + avp->noa_duration = duration + sc->sched.channel_switch_time; + + ath_dbg(common, CHAN_CTX, + "oneshot noa_duration: %d, noa_start: %u, noa_index: %d, periodic: %d\n", + avp->noa_duration, + avp->noa_start, + avp->noa_index, + avp->periodic_noa); +} + +void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, + enum ath_chanctx_event ev) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_beacon_config *cur_conf; + struct ath_vif *avp = NULL; + struct ath_chanctx *ctx; + u32 tsf_time; + u32 beacon_int; + + if (vif) + avp = (struct ath_vif *) vif->drv_priv; + + spin_lock_bh(&sc->chan_lock); + + ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s, delta: %u ms\n", + sc->cur_chan->chandef.center_freq1, + chanctx_event_string(ev), + chanctx_state_string(sc->sched.state), + chanctx_event_delta(sc)); + + switch (ev) { + case ATH_CHANCTX_EVENT_BEACON_PREPARE: + if (avp->offchannel_duration) + avp->offchannel_duration = 0; + + if (avp->oneshot_noa) { + avp->noa_duration = 0; + avp->oneshot_noa = false; + + ath_dbg(common, CHAN_CTX, + "Clearing oneshot NoA\n"); + } + + if (avp->chanctx != sc->cur_chan) { + ath_dbg(common, CHAN_CTX, + "Contexts differ, not preparing beacon\n"); + break; + } + + if (sc->sched.offchannel_pending && !sc->sched.wait_switch) { + sc->sched.offchannel_pending = false; + sc->next_chan = &sc->offchannel.chan; + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; + ath_dbg(common, CHAN_CTX, + "Setting offchannel_pending to false\n"); + } + + ctx = ath_chanctx_get_next(sc, sc->cur_chan); + if (ctx->active && sc->sched.state == ATH_CHANCTX_STATE_IDLE) { + sc->next_chan = ctx; + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; + ath_dbg(common, CHAN_CTX, + "Set next context, move chanctx state to WAIT_FOR_BEACON\n"); + } + + /* if the timer missed its window, use the next interval */ + if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER) { + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; + ath_dbg(common, CHAN_CTX, + "Move chanctx state from WAIT_FOR_TIMER to WAIT_FOR_BEACON\n"); + } + + if (sc->sched.mgd_prepare_tx) + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; + + /* + * When a context becomes inactive, for example, + * disassociation of a station context, the NoA + * attribute needs to be removed from subsequent + * beacons. + */ + if (!ctx->active && avp->noa_duration && + sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) { + avp->noa_duration = 0; + avp->periodic_noa = false; + + ath_dbg(common, CHAN_CTX, + "Clearing NoA schedule\n"); + } + + if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) + break; + + ath_dbg(common, CHAN_CTX, "Preparing beacon for vif: %pM\n", vif->addr); + + sc->sched.beacon_pending = true; + sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER); + + cur_conf = &sc->cur_chan->beacon; + beacon_int = TU_TO_USEC(cur_conf->beacon_interval); + + /* defer channel switch by a quarter beacon interval */ + tsf_time = sc->sched.next_tbtt + beacon_int / 4; + sc->sched.switch_start_time = tsf_time; + sc->cur_chan->last_beacon = sc->sched.next_tbtt; + + /* + * If an offchannel switch is scheduled to happen after + * a beacon transmission, update the NoA with one-shot + * values and increment the index. + */ + if (sc->next_chan == &sc->offchannel.chan) { + ath_chanctx_offchannel_noa(sc, ctx, avp, tsf_time); + break; + } + + ath_chanctx_handle_bmiss(sc, ctx, avp); + + /* + * If a mgd_prepare_tx() has been called by mac80211, + * a one-shot NoA needs to be sent. This can happen + * with one or more active channel contexts - in both + * cases, a new NoA schedule has to be advertised. + */ + if (sc->sched.mgd_prepare_tx) { + ath_chanctx_set_oneshot_noa(sc, avp, tsf_time, + jiffies_to_usecs(HZ / 5)); + break; + } + + /* Prevent wrap-around issues */ + if (avp->noa_duration && tsf_time - avp->noa_start > BIT(30)) + avp->noa_duration = 0; + + /* + * If multiple contexts are active, start periodic + * NoA and increment the index for the first + * announcement. + */ + if (ctx->active && + (!avp->noa_duration || sc->sched.force_noa_update)) + ath_chanctx_set_periodic_noa(sc, avp, cur_conf, + tsf_time, beacon_int); + + if (ctx->active && sc->sched.force_noa_update) + sc->sched.force_noa_update = false; + + break; + case ATH_CHANCTX_EVENT_BEACON_SENT: + if (!sc->sched.beacon_pending) { + ath_dbg(common, CHAN_CTX, + "No pending beacon\n"); + break; + } + + sc->sched.beacon_pending = false; + + if (sc->sched.mgd_prepare_tx) { + sc->sched.mgd_prepare_tx = false; + complete(&sc->go_beacon); + ath_dbg(common, CHAN_CTX, + "Beacon sent, complete go_beacon\n"); + break; + } + + if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) + break; + + ath_dbg(common, CHAN_CTX, + "Move chanctx state to WAIT_FOR_TIMER\n"); + + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; + ath_chanctx_setup_timer(sc, sc->sched.switch_start_time); + break; + case ATH_CHANCTX_EVENT_TSF_TIMER: + if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_TIMER) + break; + + if (!sc->cur_chan->switch_after_beacon && + sc->sched.beacon_pending) + sc->sched.beacon_miss++; + + ath_dbg(common, CHAN_CTX, + "Move chanctx state to SWITCH\n"); + + sc->sched.state = ATH_CHANCTX_STATE_SWITCH; + ieee80211_queue_work(sc->hw, &sc->chanctx_work); + break; + case ATH_CHANCTX_EVENT_BEACON_RECEIVED: + if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) || + sc->cur_chan == &sc->offchannel.chan) + break; + + sc->sched.beacon_pending = false; + sc->sched.beacon_miss = 0; + + if (sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE || + !sc->sched.beacon_adjust || + !sc->cur_chan->tsf_val) + break; + + ath_chanctx_adjust_tbtt_delta(sc); + + /* TSF time might have been updated by the incoming beacon, + * need update the channel switch timer to reflect the change. + */ + tsf_time = sc->sched.switch_start_time; + tsf_time -= (u32) sc->cur_chan->tsf_val + + ath9k_hw_get_tsf_offset(sc->cur_chan->tsf_ts, 0); + tsf_time += ath9k_hw_gettsf32(ah); + + sc->sched.beacon_adjust = false; + ath_chanctx_setup_timer(sc, tsf_time); + break; + case ATH_CHANCTX_EVENT_AUTHORIZED: + if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE || + avp->chanctx != sc->cur_chan) + break; + + ath_dbg(common, CHAN_CTX, + "Move chanctx state from FORCE_ACTIVE to IDLE\n"); + + sc->sched.state = ATH_CHANCTX_STATE_IDLE; + fallthrough; + case ATH_CHANCTX_EVENT_SWITCH: + if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) || + sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE || + sc->cur_chan->switch_after_beacon || + sc->cur_chan == &sc->offchannel.chan) + break; + + /* If this is a station chanctx, stay active for a half + * beacon period (minus channel switch time) + */ + sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan); + cur_conf = &sc->cur_chan->beacon; + + ath_dbg(common, CHAN_CTX, + "Move chanctx state to WAIT_FOR_TIMER (event SWITCH)\n"); + + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER; + sc->sched.wait_switch = false; + + tsf_time = TU_TO_USEC(cur_conf->beacon_interval) / 2; + + if (sc->sched.extend_absence) { + sc->sched.beacon_miss = 0; + tsf_time *= 3; + } + + tsf_time -= sc->sched.channel_switch_time; + tsf_time += ath9k_hw_gettsf32(sc->sc_ah); + sc->sched.switch_start_time = tsf_time; + + ath_chanctx_setup_timer(sc, tsf_time); + sc->sched.beacon_pending = true; + sc->sched.beacon_adjust = true; + break; + case ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL: + if (sc->cur_chan == &sc->offchannel.chan || + sc->cur_chan->switch_after_beacon) + break; + + sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan); + ieee80211_queue_work(sc->hw, &sc->chanctx_work); + break; + case ATH_CHANCTX_EVENT_UNASSIGN: + if (sc->cur_chan->assigned) { + if (sc->next_chan && !sc->next_chan->assigned && + sc->next_chan != &sc->offchannel.chan) + sc->sched.state = ATH_CHANCTX_STATE_IDLE; + break; + } + + ctx = ath_chanctx_get_next(sc, sc->cur_chan); + sc->sched.state = ATH_CHANCTX_STATE_IDLE; + if (!ctx->assigned) + break; + + sc->next_chan = ctx; + ieee80211_queue_work(sc->hw, &sc->chanctx_work); + break; + case ATH_CHANCTX_EVENT_ASSIGN: + break; + case ATH_CHANCTX_EVENT_CHANGE: + break; + } + + spin_unlock_bh(&sc->chan_lock); +} + +void ath_chanctx_beacon_sent_ev(struct ath_softc *sc, + enum ath_chanctx_event ev) +{ + if (sc->sched.beacon_pending) + ath_chanctx_event(sc, NULL, ev); +} + +void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, + enum ath_chanctx_event ev) +{ + ath_chanctx_event(sc, NULL, ev); +} + +static int ath_scan_channel_duration(struct ath_softc *sc, + struct ieee80211_channel *chan) +{ + struct cfg80211_scan_request *req = sc->offchannel.scan_req; + + if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR)) + return (HZ / 9); /* ~110 ms */ + + return (HZ / 16); /* ~60 ms */ +} + +static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx, + struct cfg80211_chan_def *chandef) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + spin_lock_bh(&sc->chan_lock); + + if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) && + (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) { + if (chandef) + ctx->chandef = *chandef; + + sc->sched.offchannel_pending = true; + sc->sched.wait_switch = true; + sc->sched.offchannel_duration = + jiffies_to_usecs(sc->offchannel.duration) + + sc->sched.channel_switch_time; + + spin_unlock_bh(&sc->chan_lock); + ath_dbg(common, CHAN_CTX, + "Set offchannel_pending to true\n"); + return; + } + + sc->next_chan = ctx; + if (chandef) { + ctx->chandef = *chandef; + ath_dbg(common, CHAN_CTX, + "Assigned next_chan to %d MHz\n", chandef->center_freq1); + } + + if (sc->next_chan == &sc->offchannel.chan) { + sc->sched.offchannel_duration = + jiffies_to_usecs(sc->offchannel.duration) + + sc->sched.channel_switch_time; + + if (chandef) { + ath_dbg(common, CHAN_CTX, + "Offchannel duration for chan %d MHz : %u\n", + chandef->center_freq1, + sc->sched.offchannel_duration); + } + } + spin_unlock_bh(&sc->chan_lock); + ieee80211_queue_work(sc->hw, &sc->chanctx_work); +} + +static void ath_chanctx_offchan_switch(struct ath_softc *sc, + struct ieee80211_channel *chan) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct cfg80211_chan_def chandef; + + cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); + ath_dbg(common, CHAN_CTX, + "Channel definition created: %d MHz\n", chandef.center_freq1); + + ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef); +} + +static struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, + bool active) +{ + struct ath_chanctx *ctx; + + ath_for_each_chanctx(sc, ctx) { + if (!ctx->assigned || list_empty(&ctx->vifs)) + continue; + if (active && !ctx->active) + continue; + + if (ctx->switch_after_beacon) + return ctx; + } + + return &sc->chanctx[0]; +} + +static void +ath_scan_next_channel(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct cfg80211_scan_request *req = sc->offchannel.scan_req; + struct ieee80211_channel *chan; + + if (sc->offchannel.scan_idx >= req->n_channels) { + ath_dbg(common, CHAN_CTX, + "Moving offchannel state to ATH_OFFCHANNEL_IDLE, " + "scan_idx: %d, n_channels: %d\n", + sc->offchannel.scan_idx, + req->n_channels); + + sc->offchannel.state = ATH_OFFCHANNEL_IDLE; + ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false), + NULL); + return; + } + + ath_dbg(common, CHAN_CTX, + "Moving offchannel state to ATH_OFFCHANNEL_PROBE_SEND, scan_idx: %d\n", + sc->offchannel.scan_idx); + + chan = req->channels[sc->offchannel.scan_idx++]; + sc->offchannel.duration = ath_scan_channel_duration(sc, chan); + sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND; + + ath_chanctx_offchan_switch(sc, chan); +} + +void ath_offchannel_next(struct ath_softc *sc) +{ + struct ieee80211_vif *vif; + + if (sc->offchannel.scan_req) { + vif = sc->offchannel.scan_vif; + sc->offchannel.chan.txpower = vif->bss_conf.txpower; + ath_scan_next_channel(sc); + } else if (sc->offchannel.roc_vif) { + vif = sc->offchannel.roc_vif; + sc->offchannel.chan.txpower = vif->bss_conf.txpower; + sc->offchannel.duration = + msecs_to_jiffies(sc->offchannel.roc_duration); + sc->offchannel.state = ATH_OFFCHANNEL_ROC_START; + ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan); + } else { + spin_lock_bh(&sc->chan_lock); + sc->sched.offchannel_pending = false; + sc->sched.wait_switch = false; + spin_unlock_bh(&sc->chan_lock); + + ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false), + NULL); + sc->offchannel.state = ATH_OFFCHANNEL_IDLE; + if (sc->ps_idle) + ath_cancel_work(sc); + } +} + +void ath_roc_complete(struct ath_softc *sc, enum ath_roc_complete_reason reason) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + sc->offchannel.roc_vif = NULL; + sc->offchannel.roc_chan = NULL; + + switch (reason) { + case ATH_ROC_COMPLETE_ABORT: + ath_dbg(common, CHAN_CTX, "RoC aborted\n"); + ieee80211_remain_on_channel_expired(sc->hw); + break; + case ATH_ROC_COMPLETE_EXPIRE: + ath_dbg(common, CHAN_CTX, "RoC expired\n"); + ieee80211_remain_on_channel_expired(sc->hw); + break; + case ATH_ROC_COMPLETE_CANCEL: + ath_dbg(common, CHAN_CTX, "RoC canceled\n"); + break; + } + + ath_offchannel_next(sc); + ath9k_ps_restore(sc); +} + +void ath_scan_complete(struct ath_softc *sc, bool abort) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct cfg80211_scan_info info = { + .aborted = abort, + }; + + if (abort) + ath_dbg(common, CHAN_CTX, "HW scan aborted\n"); + else + ath_dbg(common, CHAN_CTX, "HW scan complete\n"); + + sc->offchannel.scan_req = NULL; + sc->offchannel.scan_vif = NULL; + sc->offchannel.state = ATH_OFFCHANNEL_IDLE; + ieee80211_scan_completed(sc->hw, &info); + clear_bit(ATH_OP_SCANNING, &common->op_flags); + spin_lock_bh(&sc->chan_lock); + if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) + sc->sched.force_noa_update = true; + spin_unlock_bh(&sc->chan_lock); + ath_offchannel_next(sc); + ath9k_ps_restore(sc); +} + +static void ath_scan_send_probe(struct ath_softc *sc, + struct cfg80211_ssid *ssid) +{ + struct cfg80211_scan_request *req = sc->offchannel.scan_req; + struct ieee80211_vif *vif = sc->offchannel.scan_vif; + struct ath_tx_control txctl = {}; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + int band = sc->offchannel.chan.chandef.chan->band; + + skb = ieee80211_probereq_get(sc->hw, vif->addr, + ssid->ssid, ssid->ssid_len, req->ie_len); + if (!skb) + return; + + info = IEEE80211_SKB_CB(skb); + if (req->no_cck) + info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE; + + if (req->ie_len) + skb_put_data(skb, req->ie, req->ie_len); + + skb_set_queue_mapping(skb, IEEE80211_AC_VO); + + if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL)) + goto error; + + txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; + if (ath_tx_start(sc->hw, skb, &txctl)) + goto error; + + return; + +error: + ieee80211_free_txskb(sc->hw, skb); +} + +static void ath_scan_channel_start(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct cfg80211_scan_request *req = sc->offchannel.scan_req; + int i; + + if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) && + req->n_ssids) { + for (i = 0; i < req->n_ssids; i++) + ath_scan_send_probe(sc, &req->ssids[i]); + + } + + ath_dbg(common, CHAN_CTX, + "Moving offchannel state to ATH_OFFCHANNEL_PROBE_WAIT\n"); + + sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT; + mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration); +} + +static void ath_chanctx_timer(struct timer_list *t) +{ + struct ath_softc *sc = timer_container_of(sc, t, sched.timer); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + ath_dbg(common, CHAN_CTX, + "Channel context timer invoked\n"); + + ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER); +} + +static void ath_offchannel_timer(struct timer_list *t) +{ + struct ath_softc *sc = timer_container_of(sc, t, offchannel.timer); + struct ath_chanctx *ctx; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + ath_dbg(common, CHAN_CTX, "%s: offchannel state: %s\n", + __func__, offchannel_state_string(sc->offchannel.state)); + + switch (sc->offchannel.state) { + case ATH_OFFCHANNEL_PROBE_WAIT: + if (!sc->offchannel.scan_req) + return; + + /* get first active channel context */ + ctx = ath_chanctx_get_oper_chan(sc, true); + if (ctx->active) { + ath_dbg(common, CHAN_CTX, + "Switch to oper/active context, " + "move offchannel state to ATH_OFFCHANNEL_SUSPEND\n"); + + sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND; + ath_chanctx_switch(sc, ctx, NULL); + mod_timer(&sc->offchannel.timer, jiffies + HZ / 10); + break; + } + fallthrough; + case ATH_OFFCHANNEL_SUSPEND: + if (!sc->offchannel.scan_req) + return; + + ath_scan_next_channel(sc); + break; + case ATH_OFFCHANNEL_ROC_START: + case ATH_OFFCHANNEL_ROC_WAIT: + sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE; + ath_roc_complete(sc, ATH_ROC_COMPLETE_EXPIRE); + break; + default: + break; + } +} + +static bool +ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp, + bool powersave) +{ + struct ieee80211_vif *vif = avp->vif; + struct ieee80211_sta *sta = NULL; + struct ieee80211_hdr_3addr *nullfunc; + struct ath_tx_control txctl; + struct sk_buff *skb; + int band = sc->cur_chan->chandef.chan->band; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + if (!avp->assoc) + return false; + + skb = ieee80211_nullfunc_get(sc->hw, vif, -1, false); + if (!skb) + return false; + + nullfunc = (struct ieee80211_hdr_3addr *) skb->data; + if (powersave) + nullfunc->frame_control |= + cpu_to_le16(IEEE80211_FCTL_PM); + + skb->priority = 7; + skb_set_queue_mapping(skb, IEEE80211_AC_VO); + if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) { + dev_kfree_skb_any(skb); + return false; + } + break; + default: + return false; + } + + memset(&txctl, 0, sizeof(txctl)); + txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; + txctl.sta = sta; + if (ath_tx_start(sc->hw, skb, &txctl)) { + ieee80211_free_txskb(sc->hw, skb); + return false; + } + + return true; +} + +static bool +ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave) +{ + struct ath_vif *avp; + bool sent = false; + + rcu_read_lock(); + list_for_each_entry(avp, &sc->cur_chan->vifs, list) { + if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave)) + sent = true; + } + rcu_read_unlock(); + + return sent; +} + +static bool ath_chanctx_defer_switch(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + if (sc->cur_chan == &sc->offchannel.chan) + return false; + + switch (sc->sched.state) { + case ATH_CHANCTX_STATE_SWITCH: + return false; + case ATH_CHANCTX_STATE_IDLE: + if (!sc->cur_chan->switch_after_beacon) + return false; + + ath_dbg(common, CHAN_CTX, + "Defer switch, set chanctx state to WAIT_FOR_BEACON\n"); + + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; + break; + default: + break; + } + + return true; +} + +static void ath_offchannel_channel_change(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + ath_dbg(common, CHAN_CTX, "%s: offchannel state: %s\n", + __func__, offchannel_state_string(sc->offchannel.state)); + + switch (sc->offchannel.state) { + case ATH_OFFCHANNEL_PROBE_SEND: + if (!sc->offchannel.scan_req) + return; + + if (sc->cur_chan->chandef.chan != + sc->offchannel.chan.chandef.chan) + return; + + ath_scan_channel_start(sc); + break; + case ATH_OFFCHANNEL_IDLE: + if (!sc->offchannel.scan_req) + return; + + ath_scan_complete(sc, false); + break; + case ATH_OFFCHANNEL_ROC_START: + if (sc->cur_chan != &sc->offchannel.chan) + break; + + sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT; + mod_timer(&sc->offchannel.timer, + jiffies + sc->offchannel.duration); + ieee80211_ready_on_channel(sc->hw); + break; + case ATH_OFFCHANNEL_ROC_DONE: + break; + default: + break; + } +} + +void ath_chanctx_set_next(struct ath_softc *sc, bool force) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_chanctx *old_ctx; + bool measure_time = false; + bool send_ps = false; + bool queues_stopped = false; + ktime_t ts; + + spin_lock_bh(&sc->chan_lock); + if (!sc->next_chan) { + spin_unlock_bh(&sc->chan_lock); + return; + } + + if (!force && ath_chanctx_defer_switch(sc)) { + spin_unlock_bh(&sc->chan_lock); + return; + } + + ath_dbg(common, CHAN_CTX, + "%s: current: %d MHz, next: %d MHz\n", + __func__, + sc->cur_chan->chandef.center_freq1, + sc->next_chan->chandef.center_freq1); + + if (sc->cur_chan != sc->next_chan) { + ath_dbg(common, CHAN_CTX, + "Stopping current chanctx: %d\n", + sc->cur_chan->chandef.center_freq1); + sc->cur_chan->stopped = true; + spin_unlock_bh(&sc->chan_lock); + + if (sc->next_chan == &sc->offchannel.chan) { + ts = ktime_get_raw(); + measure_time = true; + } + + ath9k_chanctx_stop_queues(sc, sc->cur_chan); + queues_stopped = true; + + __ath9k_flush(sc->hw, ~0, true, false, false); + + if (ath_chanctx_send_ps_frame(sc, true)) + __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), + false, false, false); + + send_ps = true; + spin_lock_bh(&sc->chan_lock); + + if (sc->cur_chan != &sc->offchannel.chan) { + sc->cur_chan->tsf_ts = ktime_get_raw(); + sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah); + } + } + old_ctx = sc->cur_chan; + sc->cur_chan = sc->next_chan; + sc->cur_chan->stopped = false; + sc->next_chan = NULL; + + if (!sc->sched.offchannel_pending) + sc->sched.offchannel_duration = 0; + + if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE) + sc->sched.state = ATH_CHANCTX_STATE_IDLE; + + spin_unlock_bh(&sc->chan_lock); + + if (sc->sc_ah->chip_fullsleep || + memcmp(&sc->cur_chandef, &sc->cur_chan->chandef, + sizeof(sc->cur_chandef))) { + ath_dbg(common, CHAN_CTX, + "%s: Set channel %d MHz\n", + __func__, sc->cur_chan->chandef.center_freq1); + ath_set_channel(sc); + if (measure_time) + sc->sched.channel_switch_time = + ath9k_hw_get_tsf_offset(ts, 0); + /* + * A reset will ensure that all queues are woken up, + * so there is no need to awaken them again. + */ + goto out; + } + + if (queues_stopped) + ath9k_chanctx_wake_queues(sc, old_ctx); +out: + if (send_ps) + ath_chanctx_send_ps_frame(sc, false); + + ath_offchannel_channel_change(sc); + ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH); +} + +static void ath_chanctx_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + chanctx_work); + mutex_lock(&sc->mutex); + ath_chanctx_set_next(sc, false); + mutex_unlock(&sc->mutex); +} + +void ath9k_offchannel_init(struct ath_softc *sc) +{ + struct ath_chanctx *ctx; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + int i; + + sband = &common->sbands[NL80211_BAND_2GHZ]; + if (!sband->n_channels) + sband = &common->sbands[NL80211_BAND_5GHZ]; + + chan = &sband->channels[0]; + + ctx = &sc->offchannel.chan; + INIT_LIST_HEAD(&ctx->vifs); + ctx->txpower = ATH_TXPOWER_MAX; + cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20); + + for (i = 0; i < ARRAY_SIZE(ctx->acq); i++) { + INIT_LIST_HEAD(&ctx->acq[i].acq_new); + INIT_LIST_HEAD(&ctx->acq[i].acq_old); + spin_lock_init(&ctx->acq[i].lock); + } + + sc->offchannel.chan.offchannel = true; +} + +void ath9k_init_channel_context(struct ath_softc *sc) +{ + INIT_WORK(&sc->chanctx_work, ath_chanctx_work); + + timer_setup(&sc->offchannel.timer, ath_offchannel_timer, 0); + timer_setup(&sc->sched.timer, ath_chanctx_timer, 0); + + init_completion(&sc->go_beacon); +} + +void ath9k_deinit_channel_context(struct ath_softc *sc) +{ + cancel_work_sync(&sc->chanctx_work); +} + +bool ath9k_is_chanctx_enabled(void) +{ + return (ath9k_use_chanctx == 1); +} + +/********************/ +/* Queue management */ +/********************/ + +void ath9k_chanctx_stop_queues(struct ath_softc *sc, struct ath_chanctx *ctx) +{ + struct ath_hw *ah = sc->sc_ah; + int i; + + if (ctx == &sc->offchannel.chan) { + ieee80211_stop_queue(sc->hw, + sc->hw->offchannel_tx_hw_queue); + } else { + for (i = 0; i < IEEE80211_NUM_ACS; i++) + ieee80211_stop_queue(sc->hw, + ctx->hw_queue_base + i); + } + + if (ah->opmode == NL80211_IFTYPE_AP) + ieee80211_stop_queue(sc->hw, sc->hw->queues - 2); +} + + +void ath9k_chanctx_wake_queues(struct ath_softc *sc, struct ath_chanctx *ctx) +{ + struct ath_hw *ah = sc->sc_ah; + int i; + + if (ctx == &sc->offchannel.chan) { + ieee80211_wake_queue(sc->hw, + sc->hw->offchannel_tx_hw_queue); + } else { + for (i = 0; i < IEEE80211_NUM_ACS; i++) + ieee80211_wake_queue(sc->hw, + ctx->hw_queue_base + i); + } + + if (ah->opmode == NL80211_IFTYPE_AP) + ieee80211_wake_queue(sc->hw, sc->hw->queues - 2); +} + +/*****************/ +/* P2P Powersave */ +/*****************/ + +static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + u32 tsf, target_tsf; + + if (!avp || !avp->noa.has_next_tsf) + return; + + ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer); + + tsf = ath9k_hw_gettsf32(sc->sc_ah); + + target_tsf = avp->noa.next_tsf; + if (!avp->noa.absent) + target_tsf -= ATH_P2P_PS_STOP_TIME; + else + target_tsf += ATH_P2P_PS_STOP_TIME; + + if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME) + target_tsf = tsf + ATH_P2P_PS_STOP_TIME; + + ath_dbg(common, CHAN_CTX, "%s absent %d tsf 0x%08X next_tsf 0x%08X (%dms)\n", + __func__, avp->noa.absent, tsf, target_tsf, + (target_tsf - tsf) / 1000); + + ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, target_tsf, 1000000); +} + +static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + struct ath_vif *avp = (void *)vif->drv_priv; + u32 tsf; + + if (!sc->p2p_ps_timer) + return; + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + sc->p2p_ps_vif = avp; + + if (sc->ps_flags & PS_BEACON_SYNC) + return; + + tsf = ath9k_hw_gettsf32(sc->sc_ah); + ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf); + ath9k_update_p2p_ps_timer(sc, avp); +} + +static u8 ath9k_get_ctwin(struct ath_softc *sc, struct ath_vif *avp) +{ + struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; + u8 switch_time, ctwin; + + /* + * Channel switch in multi-channel mode is deferred + * by a quarter beacon interval when handling + * ATH_CHANCTX_EVENT_BEACON_PREPARE, so the P2P-GO + * interface is guaranteed to be discoverable + * for that duration after a TBTT. + */ + switch_time = cur_conf->beacon_interval / 4; + + ctwin = avp->vif->bss_conf.p2p_noa_attr.oppps_ctwindow; + if (ctwin && (ctwin < switch_time)) + return ctwin; + + if (switch_time < P2P_DEFAULT_CTWIN) + return 0; + + return P2P_DEFAULT_CTWIN; +} + +void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp, + struct sk_buff *skb) +{ + static const u8 noa_ie_hdr[] = { + WLAN_EID_VENDOR_SPECIFIC, /* type */ + 0, /* length */ + 0x50, 0x6f, 0x9a, /* WFA OUI */ + 0x09, /* P2P subtype */ + 0x0c, /* Notice of Absence */ + 0x00, /* LSB of little-endian len */ + 0x00, /* MSB of little-endian len */ + }; + + struct ieee80211_p2p_noa_attr *noa; + int noa_len, noa_desc, i = 0; + u8 *hdr; + + if (!avp->offchannel_duration && !avp->noa_duration) + return; + + noa_desc = !!avp->offchannel_duration + !!avp->noa_duration; + noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc; + + hdr = skb_put_data(skb, noa_ie_hdr, sizeof(noa_ie_hdr)); + hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2; + hdr[7] = noa_len; + + noa = skb_put_zero(skb, noa_len); + + noa->index = avp->noa_index; + noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp); + if (noa->oppps_ctwindow) + noa->oppps_ctwindow |= BIT(7); + + if (avp->noa_duration) { + if (avp->periodic_noa) { + u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval); + noa->desc[i].count = 255; + noa->desc[i].interval = cpu_to_le32(interval); + } else { + noa->desc[i].count = 1; + } + + noa->desc[i].start_time = cpu_to_le32(avp->noa_start); + noa->desc[i].duration = cpu_to_le32(avp->noa_duration); + i++; + } + + if (avp->offchannel_duration) { + noa->desc[i].count = 1; + noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start); + noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration); + } +} + +void ath9k_p2p_ps_timer(void *priv) +{ + struct ath_softc *sc = priv; + struct ath_vif *avp = sc->p2p_ps_vif; + struct ieee80211_vif *vif; + struct ieee80211_sta *sta; + struct ath_node *an; + u32 tsf; + + timer_delete_sync(&sc->sched.timer); + ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer); + ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER); + + if (!avp || avp->chanctx != sc->cur_chan) + return; + + tsf = ath9k_hw_gettsf32(sc->sc_ah); + if (!avp->noa.absent) + tsf += ATH_P2P_PS_STOP_TIME; + else + tsf -= ATH_P2P_PS_STOP_TIME; + + if (!avp->noa.has_next_tsf || + avp->noa.next_tsf - tsf > BIT(31)) + ieee80211_update_p2p_noa(&avp->noa, tsf); + + ath9k_update_p2p_ps_timer(sc, avp); + + rcu_read_lock(); + + vif = avp->vif; + sta = ieee80211_find_sta(vif, avp->bssid); + if (!sta) + goto out; + + an = (void *) sta->drv_priv; + if (an->sleeping == !!avp->noa.absent) + goto out; + + an->sleeping = avp->noa.absent; + if (an->sleeping) + ath_tx_aggr_sleep(sta, sc, an); + else + ath_tx_aggr_wakeup(sc, an); + +out: + rcu_read_unlock(); +} + +void ath9k_p2p_bss_info_changed(struct ath_softc *sc, + struct ieee80211_vif *vif) +{ + unsigned long flags; + + spin_lock_bh(&sc->sc_pcu_lock); + spin_lock_irqsave(&sc->sc_pm_lock, flags); + ath9k_update_p2p_ps(sc, vif); + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); + spin_unlock_bh(&sc->sc_pcu_lock); +} + +void ath9k_p2p_beacon_sync(struct ath_softc *sc) +{ + if (sc->p2p_ps_vif) + ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif); +} + +void ath9k_p2p_remove_vif(struct ath_softc *sc, + struct ieee80211_vif *vif) +{ + struct ath_vif *avp = (void *)vif->drv_priv; + + spin_lock_bh(&sc->sc_pcu_lock); + if (avp == sc->p2p_ps_vif) { + sc->p2p_ps_vif = NULL; + ath9k_update_p2p_ps_timer(sc, NULL); + } + spin_unlock_bh(&sc->sc_pcu_lock); +} + +int ath9k_init_p2p(struct ath_softc *sc) +{ + sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer, + NULL, sc, AR_FIRST_NDP_TIMER); + if (!sc->p2p_ps_timer) + return -ENOMEM; + + return 0; +} + +void ath9k_deinit_p2p(struct ath_softc *sc) +{ + if (sc->p2p_ps_timer) + ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer); +} + +#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c new file mode 100644 index 000000000000..e4df89f2fa03 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-beacon.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/export.h> +#include "common.h" + +#define FUDGE 2 + +static u32 ath9k_get_next_tbtt(struct ath_hw *ah, u64 tsf, + unsigned int interval) +{ + unsigned int offset, divisor; + + tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time); + divisor = TU_TO_USEC(interval); + div_u64_rem(tsf, divisor, &offset); + + return (u32) tsf + divisor - offset; +} + +/* + * 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. + */ +int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, + struct ath_beacon_config *conf, + struct ath9k_beacon_state *bs) +{ + struct ath_common *common = ath9k_hw_common(ah); + int dtim_intval; + u64 tsf; + + /* No need to configure beacon if we are not associated */ + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { + ath_dbg(common, BEACON, + "STA is not yet associated..skipping beacon config\n"); + return -EPERM; + } + + memset(bs, 0, sizeof(*bs)); + conf->intval = conf->beacon_interval; + + /* + * Setup dtim parameters according to + * last beacon we received (which may be none). + */ + dtim_intval = conf->intval * conf->dtim_period; + + /* + * Pull nexttbtt forward to reflect the current + * TSF and calculate dtim state for the result. + */ + tsf = ath9k_hw_gettsf64(ah); + conf->nexttbtt = ath9k_get_next_tbtt(ah, tsf, conf->intval); + + bs->bs_intval = TU_TO_USEC(conf->intval); + bs->bs_dtimperiod = conf->dtim_period * bs->bs_intval; + bs->bs_nexttbtt = conf->nexttbtt; + bs->bs_nextdtim = conf->nexttbtt; + if (conf->dtim_period > 1) + bs->bs_nextdtim = ath9k_get_next_tbtt(ah, tsf, dtim_intval); + + /* + * Calculate the number of consecutive beacons to miss* before taking + * a BMISS interrupt. The configuration is specified in TU so we only + * need calculate based on the beacon interval. Note that we clamp the + * result to at most 15 beacons. + */ + bs->bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, conf->intval); + if (bs->bs_bmissthreshold > 15) + bs->bs_bmissthreshold = 15; + else if (bs->bs_bmissthreshold <= 0) + bs->bs_bmissthreshold = 1; + + /* + * Calculate sleep duration. The configuration is given in ms. + * We ensure 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 = TU_TO_USEC(roundup(IEEE80211_MS_TO_TU(100), + conf->intval)); + if (bs->bs_sleepduration > bs->bs_dtimperiod) + bs->bs_sleepduration = bs->bs_dtimperiod; + + /* TSF out of range threshold fixed at 1 second */ + bs->bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; + + ath_dbg(common, BEACON, "bmiss: %u sleep: %u\n", + bs->bs_bmissthreshold, bs->bs_sleepduration); + return 0; +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_sta); + +void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah, + struct ath_beacon_config *conf) +{ + struct ath_common *common = ath9k_hw_common(ah); + + conf->intval = TU_TO_USEC(conf->beacon_interval); + + if (conf->ibss_creator) + conf->nexttbtt = conf->intval; + else + conf->nexttbtt = ath9k_get_next_tbtt(ah, ath9k_hw_gettsf64(ah), + conf->beacon_interval); + + if (conf->enable_beacon) + ah->imask |= ATH9K_INT_SWBA; + else + ah->imask &= ~ATH9K_INT_SWBA; + + ath_dbg(common, BEACON, + "IBSS (%s) nexttbtt: %u intval: %u conf_intval: %u\n", + (conf->enable_beacon) ? "Enable" : "Disable", + conf->nexttbtt, conf->intval, conf->beacon_interval); +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_adhoc); + +/* + * For multi-bss ap 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. + */ +void ath9k_cmn_beacon_config_ap(struct ath_hw *ah, + struct ath_beacon_config *conf, + unsigned int bc_buf) +{ + struct ath_common *common = ath9k_hw_common(ah); + + /* NB: the beacon interval is kept internally in TU's */ + conf->intval = TU_TO_USEC(conf->beacon_interval); + conf->intval /= bc_buf; + conf->nexttbtt = ath9k_get_next_tbtt(ah, ath9k_hw_gettsf64(ah), + conf->beacon_interval); + + if (conf->enable_beacon) + ah->imask |= ATH9K_INT_SWBA; + else + ah->imask &= ~ATH9K_INT_SWBA; + + ath_dbg(common, BEACON, + "AP (%s) nexttbtt: %u intval: %u conf_intval: %u\n", + (conf->enable_beacon) ? "Enable" : "Disable", + conf->nexttbtt, conf->intval, conf->beacon_interval); +} +EXPORT_SYMBOL(ath9k_cmn_beacon_config_ap); diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.h b/drivers/net/wireless/ath/ath9k/common-beacon.h new file mode 100644 index 000000000000..3665d27f0dc7 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-beacon.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2009-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct ath_beacon_config; + +int ath9k_cmn_beacon_config_sta(struct ath_hw *ah, + struct ath_beacon_config *conf, + struct ath9k_beacon_state *bs); +void ath9k_cmn_beacon_config_adhoc(struct ath_hw *ah, + struct ath_beacon_config *conf); +void ath9k_cmn_beacon_config_ap(struct ath_hw *ah, + struct ath_beacon_config *conf, + unsigned int bc_buf); diff --git a/drivers/net/wireless/ath/ath9k/common-debug.c b/drivers/net/wireless/ath/ath9k/common-debug.c new file mode 100644 index 000000000000..1ea070200e4a --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-debug.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/export.h> +#include "common.h" + +static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_hw *ah = file->private_data; + u32 len = 0, size = 6000; + char *buf; + size_t retval; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len = ah->eep_ops->dump_eeprom(ah, false, buf, len, size); + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_modal_eeprom = { + .read = read_file_modal_eeprom, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + + +void ath9k_cmn_debug_modal_eeprom(struct dentry *debugfs_phy, + struct ath_hw *ah) +{ + debugfs_create_file("modal_eeprom", 0400, debugfs_phy, ah, + &fops_modal_eeprom); +} +EXPORT_SYMBOL(ath9k_cmn_debug_modal_eeprom); + +static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_hw *ah = file->private_data; + u32 len = 0, size = 1500; + ssize_t retval = 0; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len = ah->eep_ops->dump_eeprom(ah, true, buf, len, size); + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_base_eeprom = { + .read = read_file_base_eeprom, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_cmn_debug_base_eeprom(struct dentry *debugfs_phy, + struct ath_hw *ah) +{ + debugfs_create_file("base_eeprom", 0400, debugfs_phy, ah, + &fops_base_eeprom); +} +EXPORT_SYMBOL(ath9k_cmn_debug_base_eeprom); + +void ath9k_cmn_debug_stat_rx(struct ath_rx_stats *rxstats, + struct ath_rx_status *rs) +{ +#define RX_PHY_ERR_INC(c) rxstats->phy_err_stats[c]++ +#define RX_CMN_STAT_INC(c) (rxstats->c++) + + RX_CMN_STAT_INC(rx_pkts_all); + rxstats->rx_bytes_all += rs->rs_datalen; + + if (rs->rs_status & ATH9K_RXERR_CRC) + RX_CMN_STAT_INC(crc_err); + if (rs->rs_status & ATH9K_RXERR_DECRYPT) + RX_CMN_STAT_INC(decrypt_crc_err); + if (rs->rs_status & ATH9K_RXERR_MIC) + RX_CMN_STAT_INC(mic_err); + if (rs->rs_status & ATH9K_RX_DELIM_CRC_PRE) + RX_CMN_STAT_INC(pre_delim_crc_err); + if (rs->rs_status & ATH9K_RX_DELIM_CRC_POST) + RX_CMN_STAT_INC(post_delim_crc_err); + if (rs->rs_status & ATH9K_RX_DECRYPT_BUSY) + RX_CMN_STAT_INC(decrypt_busy_err); + + if (rs->rs_status & ATH9K_RXERR_PHY) { + RX_CMN_STAT_INC(phy_err); + if (rs->rs_phyerr < ATH9K_PHYERR_MAX) + RX_PHY_ERR_INC(rs->rs_phyerr); + } + +#undef RX_CMN_STAT_INC +#undef RX_PHY_ERR_INC +} +EXPORT_SYMBOL(ath9k_cmn_debug_stat_rx); + +static ssize_t read_file_recv(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define RXS_ERR(s, e) \ + do { \ + len += scnprintf(buf + len, size - len, \ + "%18s : %10u\n", s, \ + rxstats->e); \ + } while (0) + + struct ath_rx_stats *rxstats = file->private_data; + char *buf; + unsigned int len = 0, size = 1600; + ssize_t retval = 0; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + RXS_ERR("PKTS-ALL", rx_pkts_all); + RXS_ERR("BYTES-ALL", rx_bytes_all); + RXS_ERR("BEACONS", rx_beacons); + RXS_ERR("FRAGS", rx_frags); + RXS_ERR("SPECTRAL", rx_spectral); + RXS_ERR("SPECTRAL SMPL GOOD", rx_spectral_sample_good); + RXS_ERR("SPECTRAL SMPL ERR", rx_spectral_sample_err); + + RXS_ERR("CRC ERR", crc_err); + RXS_ERR("DECRYPT CRC ERR", decrypt_crc_err); + RXS_ERR("PHY ERR", phy_err); + RXS_ERR("MIC ERR", mic_err); + RXS_ERR("PRE-DELIM CRC ERR", pre_delim_crc_err); + RXS_ERR("POST-DELIM CRC ERR", post_delim_crc_err); + RXS_ERR("DECRYPT BUSY ERR", decrypt_busy_err); + RXS_ERR("LENGTH-ERR", rx_len_err); + RXS_ERR("OOM-ERR", rx_oom_err); + RXS_ERR("RATE-ERR", rx_rate_err); + RXS_ERR("TOO-MANY-FRAGS", rx_too_many_frags_err); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef RXS_ERR +} + +static const struct file_operations fops_recv = { + .read = read_file_recv, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_cmn_debug_recv(struct dentry *debugfs_phy, + struct ath_rx_stats *rxstats) +{ + debugfs_create_file("recv", 0400, debugfs_phy, rxstats, &fops_recv); +} +EXPORT_SYMBOL(ath9k_cmn_debug_recv); + +static ssize_t read_file_phy_err(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define PHY_ERR(s, p) \ + len += scnprintf(buf + len, size - len, "%22s : %10u\n", s, \ + rxstats->phy_err_stats[p]) + + struct ath_rx_stats *rxstats = file->private_data; + char *buf; + unsigned int len = 0, size = 1600; + ssize_t retval = 0; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); + PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING); + PHY_ERR("PARITY ERR", ATH9K_PHYERR_PARITY); + PHY_ERR("RATE ERR", ATH9K_PHYERR_RATE); + PHY_ERR("LENGTH ERR", ATH9K_PHYERR_LENGTH); + PHY_ERR("RADAR ERR", ATH9K_PHYERR_RADAR); + PHY_ERR("SERVICE ERR", ATH9K_PHYERR_SERVICE); + PHY_ERR("TOR ERR", ATH9K_PHYERR_TOR); + + PHY_ERR("OFDM-TIMING ERR", ATH9K_PHYERR_OFDM_TIMING); + PHY_ERR("OFDM-SIGNAL-PARITY ERR", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); + PHY_ERR("OFDM-RATE ERR", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); + PHY_ERR("OFDM-LENGTH ERR", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); + PHY_ERR("OFDM-POWER-DROP ERR", ATH9K_PHYERR_OFDM_POWER_DROP); + PHY_ERR("OFDM-SERVICE ERR", ATH9K_PHYERR_OFDM_SERVICE); + PHY_ERR("OFDM-RESTART ERR", ATH9K_PHYERR_OFDM_RESTART); + + PHY_ERR("CCK-BLOCKER ERR", ATH9K_PHYERR_CCK_BLOCKER); + PHY_ERR("CCK-TIMING ERR", ATH9K_PHYERR_CCK_TIMING); + PHY_ERR("CCK-HEADER-CRC ERR", ATH9K_PHYERR_CCK_HEADER_CRC); + PHY_ERR("CCK-RATE ERR", ATH9K_PHYERR_CCK_RATE_ILLEGAL); + PHY_ERR("CCK-LENGTH ERR", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); + PHY_ERR("CCK-POWER-DROP ERR", ATH9K_PHYERR_CCK_POWER_DROP); + PHY_ERR("CCK-SERVICE ERR", ATH9K_PHYERR_CCK_SERVICE); + PHY_ERR("CCK-RESTART ERR", ATH9K_PHYERR_CCK_RESTART); + + PHY_ERR("HT-CRC ERR", ATH9K_PHYERR_HT_CRC_ERROR); + PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); + PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL); + PHY_ERR("HT-ZLF ERR", ATH9K_PHYERR_HT_ZLF); + + PHY_ERR("FALSE-RADAR-EXT ERR", ATH9K_PHYERR_FALSE_RADAR_EXT); + PHY_ERR("GREEN-FIELD ERR", ATH9K_PHYERR_GREEN_FIELD); + PHY_ERR("SPECTRAL ERR", ATH9K_PHYERR_SPECTRAL); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef PHY_ERR +} + +static const struct file_operations fops_phy_err = { + .read = read_file_phy_err, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_cmn_debug_phy_err(struct dentry *debugfs_phy, + struct ath_rx_stats *rxstats) +{ + debugfs_create_file("phy_err", 0400, debugfs_phy, rxstats, + &fops_phy_err); +} +EXPORT_SYMBOL(ath9k_cmn_debug_phy_err); diff --git a/drivers/net/wireless/ath/ath9k/common-debug.h b/drivers/net/wireless/ath/ath9k/common-debug.h new file mode 100644 index 000000000000..2938b5b96b07 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-debug.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + + +/** + * struct ath_rx_stats - RX Statistics + * @rx_pkts_all: No. of total frames received, including ones that + may have had errors. + * @rx_bytes_all: No. of total bytes received, including ones that + may have had errors. + * @crc_err: No. of frames with incorrect CRC value + * @decrypt_crc_err: No. of frames whose CRC check failed after + decryption process completed + * @phy_err: No. of frames whose reception failed because the PHY + encountered an error + * @mic_err: No. of frames with incorrect TKIP MIC verification failure + * @pre_delim_crc_err: Pre-Frame delimiter CRC error detections + * @post_delim_crc_err: Post-Frame delimiter CRC error detections + * @decrypt_busy_err: Decryption interruptions counter + * @phy_err_stats: Individual PHY error statistics + * @rx_len_err: No. of frames discarded due to bad length. + * @rx_oom_err: No. of frames dropped due to OOM issues. + * @rx_rate_err: No. of frames dropped due to rate errors. + * @rx_too_many_frags_err: Frames dropped due to too-many-frags received. + * @rx_beacons: No. of beacons received. + * @rx_frags: No. of rx-fragements received. + * @rx_spectral: No of spectral packets received. + * @rx_spectral_sample_good: No. of good spectral samples + * @rx_spectral_sample_err: No. of good spectral samples + */ +struct ath_rx_stats { + u32 rx_pkts_all; + u32 rx_bytes_all; + u32 crc_err; + u32 decrypt_crc_err; + u32 phy_err; + u32 mic_err; + u32 pre_delim_crc_err; + u32 post_delim_crc_err; + u32 decrypt_busy_err; + u32 phy_err_stats[ATH9K_PHYERR_MAX]; + u32 rx_len_err; + u32 rx_oom_err; + u32 rx_rate_err; + u32 rx_too_many_frags_err; + u32 rx_beacons; + u32 rx_frags; + u32 rx_spectral; + u32 rx_spectral_sample_good; + u32 rx_spectral_sample_err; +}; + +#ifdef CONFIG_ATH9K_COMMON_DEBUG +void ath9k_cmn_debug_modal_eeprom(struct dentry *debugfs_phy, + struct ath_hw *ah); +void ath9k_cmn_debug_base_eeprom(struct dentry *debugfs_phy, + struct ath_hw *ah); +void ath9k_cmn_debug_stat_rx(struct ath_rx_stats *rxstats, + struct ath_rx_status *rs); +void ath9k_cmn_debug_recv(struct dentry *debugfs_phy, + struct ath_rx_stats *rxstats); +void ath9k_cmn_debug_phy_err(struct dentry *debugfs_phy, + struct ath_rx_stats *rxstats); +#else +static inline void ath9k_cmn_debug_modal_eeprom(struct dentry *debugfs_phy, + struct ath_hw *ah) +{ +} + +static inline void ath9k_cmn_debug_base_eeprom(struct dentry *debugfs_phy, + struct ath_hw *ah) +{ +} + +static inline void ath9k_cmn_debug_stat_rx(struct ath_rx_stats *rxstats, + struct ath_rx_status *rs) +{ +} + +static inline void ath9k_cmn_debug_recv(struct dentry *debugfs_phy, + struct ath_rx_stats *rxstats) +{ +} + +static inline void ath9k_cmn_debug_phy_err(struct dentry *debugfs_phy, + struct ath_rx_stats *rxstats) +{ +} +#endif /* CONFIG_ATH9K_COMMON_DEBUG */ diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c new file mode 100644 index 000000000000..da102c791712 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-init.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2008-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* We use the hw_value as an index into our private channel structure */ + +#include <linux/export.h> +#include "common.h" + +#define CHAN2G(_freq, _idx) { \ + .band = NL80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 20, \ +} + +#define CHAN5G(_freq, _idx) { \ + .band = NL80211_BAND_5GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 20, \ +} + +/* Some 2 GHz radios are actually tunable on 2312-2732 + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static const struct ieee80211_channel ath9k_2ghz_chantable[] = { + CHAN2G(2412, 0), /* Channel 1 */ + CHAN2G(2417, 1), /* Channel 2 */ + CHAN2G(2422, 2), /* Channel 3 */ + CHAN2G(2427, 3), /* Channel 4 */ + CHAN2G(2432, 4), /* Channel 5 */ + CHAN2G(2437, 5), /* Channel 6 */ + CHAN2G(2442, 6), /* Channel 7 */ + CHAN2G(2447, 7), /* Channel 8 */ + CHAN2G(2452, 8), /* Channel 9 */ + CHAN2G(2457, 9), /* Channel 10 */ + CHAN2G(2462, 10), /* Channel 11 */ + CHAN2G(2467, 11), /* Channel 12 */ + CHAN2G(2472, 12), /* Channel 13 */ + CHAN2G(2484, 13), /* Channel 14 */ +}; + +/* Some 5 GHz radios are actually tunable on XXXX-YYYY + * on 5 MHz steps, we support the channels which we know + * we have calibration data for all cards though to make + * this static */ +static const struct ieee80211_channel ath9k_5ghz_chantable[] = { + /* _We_ call this UNII 1 */ + CHAN5G(5180, 14), /* Channel 36 */ + CHAN5G(5200, 15), /* Channel 40 */ + CHAN5G(5220, 16), /* Channel 44 */ + CHAN5G(5240, 17), /* Channel 48 */ + /* _We_ call this UNII 2 */ + CHAN5G(5260, 18), /* Channel 52 */ + CHAN5G(5280, 19), /* Channel 56 */ + CHAN5G(5300, 20), /* Channel 60 */ + CHAN5G(5320, 21), /* Channel 64 */ + /* _We_ call this "Middle band" */ + CHAN5G(5500, 22), /* Channel 100 */ + CHAN5G(5520, 23), /* Channel 104 */ + CHAN5G(5540, 24), /* Channel 108 */ + CHAN5G(5560, 25), /* Channel 112 */ + CHAN5G(5580, 26), /* Channel 116 */ + CHAN5G(5600, 27), /* Channel 120 */ + CHAN5G(5620, 28), /* Channel 124 */ + CHAN5G(5640, 29), /* Channel 128 */ + CHAN5G(5660, 30), /* Channel 132 */ + CHAN5G(5680, 31), /* Channel 136 */ + CHAN5G(5700, 32), /* Channel 140 */ + /* _We_ call this UNII 3 */ + CHAN5G(5745, 33), /* Channel 149 */ + CHAN5G(5765, 34), /* Channel 153 */ + CHAN5G(5785, 35), /* Channel 157 */ + CHAN5G(5805, 36), /* Channel 161 */ + CHAN5G(5825, 37), /* Channel 165 */ +}; + +/* Atheros hardware rate code addition for short preamble */ +#define SHPCHECK(__hw_rate, __flags) \ + ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) + +#define RATE(_bitrate, _hw_rate, _flags) { \ + .bitrate = (_bitrate), \ + .flags = (_flags), \ + .hw_value = (_hw_rate), \ + .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ +} + +static struct ieee80211_rate ath9k_legacy_rates[] = { + RATE(10, 0x1b, 0), + RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(60, 0x0b, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(90, 0x0f, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(120, 0x0a, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(180, 0x0e, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(240, 0x09, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(360, 0x0d, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(480, 0x08, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), + RATE(540, 0x0c, (IEEE80211_RATE_SUPPORTS_5MHZ | + IEEE80211_RATE_SUPPORTS_10MHZ)), +}; + +int ath9k_cmn_init_channels_rates(struct ath_common *common) +{ + struct ath_hw *ah = common->ah; + void *channels; + + BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + + ARRAY_SIZE(ath9k_5ghz_chantable) != + ATH9K_NUM_CHANNELS); + + if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { + channels = devm_kzalloc(ah->dev, + sizeof(ath9k_2ghz_chantable), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + memcpy(channels, ath9k_2ghz_chantable, + sizeof(ath9k_2ghz_chantable)); + common->sbands[NL80211_BAND_2GHZ].channels = channels; + common->sbands[NL80211_BAND_2GHZ].band = NL80211_BAND_2GHZ; + common->sbands[NL80211_BAND_2GHZ].n_channels = + ARRAY_SIZE(ath9k_2ghz_chantable); + common->sbands[NL80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; + common->sbands[NL80211_BAND_2GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates); + } + + if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { + channels = devm_kzalloc(ah->dev, + sizeof(ath9k_5ghz_chantable), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + memcpy(channels, ath9k_5ghz_chantable, + sizeof(ath9k_5ghz_chantable)); + common->sbands[NL80211_BAND_5GHZ].channels = channels; + common->sbands[NL80211_BAND_5GHZ].band = NL80211_BAND_5GHZ; + common->sbands[NL80211_BAND_5GHZ].n_channels = + ARRAY_SIZE(ath9k_5ghz_chantable); + common->sbands[NL80211_BAND_5GHZ].bitrates = + ath9k_legacy_rates + 4; + common->sbands[NL80211_BAND_5GHZ].n_bitrates = + ARRAY_SIZE(ath9k_legacy_rates) - 4; + } + return 0; +} +EXPORT_SYMBOL(ath9k_cmn_init_channels_rates); + +void ath9k_cmn_setup_ht_cap(struct ath_hw *ah, + struct ieee80211_sta_ht_cap *ht_info) +{ + struct ath_common *common = ath9k_hw_common(ah); + u8 tx_streams, rx_streams; + int i, max_streams; + + ht_info->ht_supported = true; + ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SM_PS | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) + ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; + + if (AR_SREV_9271(ah) || AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) + max_streams = 1; + else if (AR_SREV_9462(ah)) + max_streams = 2; + else if (AR_SREV_9300_20_OR_LATER(ah)) + max_streams = 3; + else + max_streams = 2; + + if (AR_SREV_9280_20_OR_LATER(ah)) { + if (max_streams >= 2) + ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; + ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + } + + /* set up supported mcs set */ + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams); + rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams); + + ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", + tx_streams, rx_streams); + + if (tx_streams != rx_streams) { + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + ht_info->mcs.tx_params |= ((tx_streams - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); + } + + for (i = 0; i < rx_streams; i++) + ht_info->mcs.rx_mask[i] = 0xff; + + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; +} +EXPORT_SYMBOL(ath9k_cmn_setup_ht_cap); + +void ath9k_cmn_reload_chainmask(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_HT)) + return; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) + ath9k_cmn_setup_ht_cap(ah, + &common->sbands[NL80211_BAND_2GHZ].ht_cap); + if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) + ath9k_cmn_setup_ht_cap(ah, + &common->sbands[NL80211_BAND_5GHZ].ht_cap); +} +EXPORT_SYMBOL(ath9k_cmn_reload_chainmask); diff --git a/drivers/net/wireless/ath/ath9k/common-init.h b/drivers/net/wireless/ath/ath9k/common-init.h new file mode 100644 index 000000000000..ac03fca5ffdd --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-init.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2009-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +int ath9k_cmn_init_channels_rates(struct ath_common *common); +void ath9k_cmn_setup_ht_cap(struct ath_hw *ah, + struct ieee80211_sta_ht_cap *ht_info); +void ath9k_cmn_reload_chainmask(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c new file mode 100644 index 000000000000..ca01a07f6630 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -0,0 +1,1085 @@ +/* + * Copyright (c) 2013 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/export.h> +#include <linux/relay.h> +#include <linux/random.h> +#include "ath9k.h" + +static s8 fix_rssi_inv_only(u8 rssi_val) +{ + if (rssi_val == 128) + rssi_val = 0; + return (s8) rssi_val; +} + +static void ath_debug_send_fft_sample(struct ath_spec_scan_priv *spec_priv, + struct fft_sample_tlv *fft_sample_tlv) +{ + int length; + if (!spec_priv->rfs_chan_spec_scan) + return; + + length = __be16_to_cpu(fft_sample_tlv->length) + + sizeof(*fft_sample_tlv); + relay_write(spec_priv->rfs_chan_spec_scan, fft_sample_tlv, length); +} + +typedef int (ath_cmn_fft_idx_validator) (u8 *sample_end, int bytes_read); + +static int +ath_cmn_max_idx_verify_ht20_fft(u8 *sample_end, int bytes_read) +{ + struct ath_ht20_mag_info *mag_info; + u8 *sample; + u16 max_magnitude; + u8 max_index; + u8 max_exp; + + /* Sanity check so that we don't read outside the read + * buffer + */ + if (bytes_read < SPECTRAL_HT20_SAMPLE_LEN - 1) + return -1; + + mag_info = (struct ath_ht20_mag_info *) (sample_end - + sizeof(struct ath_ht20_mag_info) + 1); + + sample = sample_end - SPECTRAL_HT20_SAMPLE_LEN + 1; + + max_index = spectral_max_index_ht20(mag_info->all_bins); + max_magnitude = spectral_max_magnitude(mag_info->all_bins); + + max_exp = mag_info->max_exp & 0xf; + + /* Don't try to read something outside the read buffer + * in case of a missing byte (so bins[0] will be outside + * the read buffer) + */ + if (bytes_read < SPECTRAL_HT20_SAMPLE_LEN && max_index < 1) + return -1; + + if ((sample[max_index] & 0xf8) != ((max_magnitude >> max_exp) & 0xf8)) + return -1; + else + return 0; +} + +static int +ath_cmn_max_idx_verify_ht20_40_fft(u8 *sample_end, int bytes_read) +{ + struct ath_ht20_40_mag_info *mag_info; + u8 *sample; + u16 lower_mag, upper_mag; + u8 lower_max_index, upper_max_index; + u8 max_exp; + int dc_pos = SPECTRAL_HT20_40_NUM_BINS / 2; + + /* Sanity check so that we don't read outside the read + * buffer + */ + if (bytes_read < SPECTRAL_HT20_40_SAMPLE_LEN - 1) + return -1; + + mag_info = (struct ath_ht20_40_mag_info *) (sample_end - + sizeof(struct ath_ht20_40_mag_info) + 1); + + sample = sample_end - SPECTRAL_HT20_40_SAMPLE_LEN + 1; + + lower_mag = spectral_max_magnitude(mag_info->lower_bins); + lower_max_index = spectral_max_index_ht40(mag_info->lower_bins); + + upper_mag = spectral_max_magnitude(mag_info->upper_bins); + upper_max_index = spectral_max_index_ht40(mag_info->upper_bins); + + max_exp = mag_info->max_exp & 0xf; + + /* Don't try to read something outside the read buffer + * in case of a missing byte (so bins[0] will be outside + * the read buffer) + */ + if (bytes_read < SPECTRAL_HT20_40_SAMPLE_LEN && + ((upper_max_index < 1) || (lower_max_index < 1))) + return -1; + + if (((sample[upper_max_index + dc_pos] & 0xf8) != + ((upper_mag >> max_exp) & 0xf8)) || + ((sample[lower_max_index] & 0xf8) != + ((lower_mag >> max_exp) & 0xf8))) + return -1; + else + return 0; +} + +typedef int (ath_cmn_fft_sample_handler) (struct ath_rx_status *rs, + struct ath_spec_scan_priv *spec_priv, + u8 *sample_buf, u64 tsf, u16 freq, int chan_type); + +static int +ath_cmn_process_ht20_fft(struct ath_rx_status *rs, + struct ath_spec_scan_priv *spec_priv, + u8 *sample_buf, + u64 tsf, u16 freq, int chan_type) +{ + struct fft_sample_ht20 fft_sample_20; + struct ath_common *common = ath9k_hw_common(spec_priv->ah); + struct ath_hw *ah = spec_priv->ah; + struct ath_ht20_mag_info *mag_info; + struct fft_sample_tlv *tlv; + int i = 0; + int ret = 0; + int dc_pos = SPECTRAL_HT20_NUM_BINS / 2; + u16 magnitude, tmp_mag, length; + u8 max_index, bitmap_w, max_exp; + + length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv); + fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20; + fft_sample_20.tlv.length = __cpu_to_be16(length); + fft_sample_20.freq = __cpu_to_be16(freq); + fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]); + fft_sample_20.noise = ah->noise; + + mag_info = (struct ath_ht20_mag_info *) (sample_buf + + SPECTRAL_HT20_NUM_BINS); + + magnitude = spectral_max_magnitude(mag_info->all_bins); + fft_sample_20.max_magnitude = __cpu_to_be16(magnitude); + + max_index = spectral_max_index_ht20(mag_info->all_bins); + fft_sample_20.max_index = max_index; + + bitmap_w = spectral_bitmap_weight(mag_info->all_bins); + fft_sample_20.bitmap_weight = bitmap_w; + + max_exp = mag_info->max_exp & 0xf; + fft_sample_20.max_exp = max_exp; + + fft_sample_20.tsf = __cpu_to_be64(tsf); + + memcpy(fft_sample_20.data, sample_buf, SPECTRAL_HT20_NUM_BINS); + + ath_dbg(common, SPECTRAL_SCAN, "FFT HT20 frame: max mag 0x%X," + "max_mag_idx %i\n", + magnitude >> max_exp, + max_index); + + if ((fft_sample_20.data[max_index] & 0xf8) != + ((magnitude >> max_exp) & 0xf8)) { + ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n"); + ret = -1; + } + + /* DC value (value in the middle) is the blind spot of the spectral + * sample and invalid, interpolate it. + */ + fft_sample_20.data[dc_pos] = (fft_sample_20.data[dc_pos + 1] + + fft_sample_20.data[dc_pos - 1]) / 2; + + /* Check if the maximum magnitude is indeed maximum, + * also if the maximum value was at dc_pos, calculate + * a new one (since value at dc_pos is invalid). + */ + if (max_index == dc_pos) { + tmp_mag = 0; + for (i = 0; i < dc_pos; i++) { + if (fft_sample_20.data[i] > tmp_mag) { + tmp_mag = fft_sample_20.data[i]; + fft_sample_20.max_index = i; + } + } + + magnitude = tmp_mag << max_exp; + fft_sample_20.max_magnitude = __cpu_to_be16(magnitude); + + ath_dbg(common, SPECTRAL_SCAN, + "Calculated new lower max 0x%X at %i\n", + tmp_mag, fft_sample_20.max_index); + } else + for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++) { + if (fft_sample_20.data[i] == (magnitude >> max_exp)) + ath_dbg(common, SPECTRAL_SCAN, + "Got max: 0x%X at index %i\n", + fft_sample_20.data[i], i); + + if (fft_sample_20.data[i] > (magnitude >> max_exp)) { + ath_dbg(common, SPECTRAL_SCAN, + "Got bin %i greater than max: 0x%X\n", + i, fft_sample_20.data[i]); + ret = -1; + } + } + + if (ret < 0) + return ret; + + tlv = (struct fft_sample_tlv *)&fft_sample_20; + + ath_debug_send_fft_sample(spec_priv, tlv); + + return 0; +} + +static int +ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs, + struct ath_spec_scan_priv *spec_priv, + u8 *sample_buf, + u64 tsf, u16 freq, int chan_type) +{ + struct fft_sample_ht20_40 fft_sample_40; + struct ath_common *common = ath9k_hw_common(spec_priv->ah); + struct ath_hw *ah = spec_priv->ah; + struct ath9k_hw_cal_data *caldata = ah->caldata; + struct ath_ht20_40_mag_info *mag_info; + struct fft_sample_tlv *tlv; + int dc_pos = SPECTRAL_HT20_40_NUM_BINS / 2; + int i = 0; + int ret = 0; + s16 ext_nf; + u16 lower_mag, upper_mag, tmp_mag, length; + s8 lower_rssi, upper_rssi; + u8 lower_max_index, upper_max_index; + u8 lower_bitmap_w, upper_bitmap_w, max_exp; + + if (caldata) + ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan, + caldata->nfCalHist[3].privNF); + else + ext_nf = ATH_DEFAULT_NOISE_FLOOR; + + length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv); + fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40; + fft_sample_40.tlv.length = __cpu_to_be16(length); + fft_sample_40.freq = __cpu_to_be16(freq); + fft_sample_40.channel_type = chan_type; + + if (chan_type == NL80211_CHAN_HT40PLUS) { + lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]); + upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]); + + fft_sample_40.lower_noise = ah->noise; + fft_sample_40.upper_noise = ext_nf; + } else { + lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]); + upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]); + + fft_sample_40.lower_noise = ext_nf; + fft_sample_40.upper_noise = ah->noise; + } + + fft_sample_40.lower_rssi = lower_rssi; + fft_sample_40.upper_rssi = upper_rssi; + + mag_info = (struct ath_ht20_40_mag_info *) (sample_buf + + SPECTRAL_HT20_40_NUM_BINS); + + lower_mag = spectral_max_magnitude(mag_info->lower_bins); + fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag); + + upper_mag = spectral_max_magnitude(mag_info->upper_bins); + fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag); + + lower_max_index = spectral_max_index_ht40(mag_info->lower_bins); + fft_sample_40.lower_max_index = lower_max_index; + + upper_max_index = spectral_max_index_ht40(mag_info->upper_bins); + fft_sample_40.upper_max_index = upper_max_index; + + lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins); + fft_sample_40.lower_bitmap_weight = lower_bitmap_w; + + upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins); + fft_sample_40.upper_bitmap_weight = upper_bitmap_w; + + max_exp = mag_info->max_exp & 0xf; + fft_sample_40.max_exp = max_exp; + + fft_sample_40.tsf = __cpu_to_be64(tsf); + + memcpy(fft_sample_40.data, sample_buf, SPECTRAL_HT20_40_NUM_BINS); + + ath_dbg(common, SPECTRAL_SCAN, "FFT HT20/40 frame: lower mag 0x%X," + "lower_mag_idx %i, upper mag 0x%X," + "upper_mag_idx %i\n", + lower_mag >> max_exp, + lower_max_index, + upper_mag >> max_exp, + upper_max_index); + + /* Check if we got the expected magnitude values at + * the expected bins + */ + if (((fft_sample_40.data[upper_max_index + dc_pos] & 0xf8) + != ((upper_mag >> max_exp) & 0xf8)) || + ((fft_sample_40.data[lower_max_index] & 0xf8) + != ((lower_mag >> max_exp) & 0xf8))) { + ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n"); + ret = -1; + } + + /* DC value (value in the middle) is the blind spot of the spectral + * sample and invalid, interpolate it. + */ + fft_sample_40.data[dc_pos] = (fft_sample_40.data[dc_pos + 1] + + fft_sample_40.data[dc_pos - 1]) / 2; + + /* Check if the maximum magnitudes are indeed maximum, + * also if the maximum value was at dc_pos, calculate + * a new one (since value at dc_pos is invalid). + */ + if (lower_max_index == dc_pos) { + tmp_mag = 0; + for (i = 0; i < dc_pos; i++) { + if (fft_sample_40.data[i] > tmp_mag) { + tmp_mag = fft_sample_40.data[i]; + fft_sample_40.lower_max_index = i; + } + } + + lower_mag = tmp_mag << max_exp; + fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag); + + ath_dbg(common, SPECTRAL_SCAN, + "Calculated new lower max 0x%X at %i\n", + tmp_mag, fft_sample_40.lower_max_index); + } else + for (i = 0; i < dc_pos; i++) { + if (fft_sample_40.data[i] == (lower_mag >> max_exp)) + ath_dbg(common, SPECTRAL_SCAN, + "Got lower mag: 0x%X at index %i\n", + fft_sample_40.data[i], i); + + if (fft_sample_40.data[i] > (lower_mag >> max_exp)) { + ath_dbg(common, SPECTRAL_SCAN, + "Got lower bin %i higher than max: 0x%X\n", + i, fft_sample_40.data[i]); + ret = -1; + } + } + + if (upper_max_index == dc_pos) { + tmp_mag = 0; + for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) { + if (fft_sample_40.data[i] > tmp_mag) { + tmp_mag = fft_sample_40.data[i]; + fft_sample_40.upper_max_index = i; + } + } + upper_mag = tmp_mag << max_exp; + fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag); + + ath_dbg(common, SPECTRAL_SCAN, + "Calculated new upper max 0x%X at %i\n", + tmp_mag, fft_sample_40.upper_max_index); + } else + for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) { + if (fft_sample_40.data[i] == (upper_mag >> max_exp)) + ath_dbg(common, SPECTRAL_SCAN, + "Got upper mag: 0x%X at index %i\n", + fft_sample_40.data[i], i); + + if (fft_sample_40.data[i] > (upper_mag >> max_exp)) { + ath_dbg(common, SPECTRAL_SCAN, + "Got upper bin %i higher than max: 0x%X\n", + i, fft_sample_40.data[i]); + + ret = -1; + } + } + + if (ret < 0) + return ret; + + tlv = (struct fft_sample_tlv *)&fft_sample_40; + + ath_debug_send_fft_sample(spec_priv, tlv); + + return 0; +} + +static inline void +ath_cmn_copy_fft_frame(u8 *in, u8 *out, int sample_len, int sample_bytes) +{ + switch (sample_bytes - sample_len) { + case -1: + /* First byte missing */ + memcpy(&out[1], in, + sample_len - 1); + break; + case 0: + /* Length correct, nothing to do. */ + memcpy(out, in, sample_len); + break; + case 1: + /* MAC added 2 extra bytes AND first byte + * is missing. + */ + memcpy(&out[1], in, 30); + out[31] = in[31]; + memcpy(&out[32], &in[33], + sample_len - 32); + break; + case 2: + /* MAC added 2 extra bytes at bin 30 and 32, + * remove them. + */ + memcpy(out, in, 30); + out[30] = in[31]; + memcpy(&out[31], &in[33], + sample_len - 31); + break; + default: + break; + } +} + +static int +ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv *spec_priv) +{ + int i = 0; + int ret = 0; + struct rchan_buf *buf; + struct rchan *rc = spec_priv->rfs_chan_spec_scan; + + for_each_possible_cpu(i) { + if ((buf = *per_cpu_ptr(rc->buf, i))) { + ret += relay_buf_full(buf); + } + } + + if (ret) + return 1; + else + return 0; +} + +/* returns 1 if this was a spectral frame, even if not handled. */ +int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_hdr *hdr, + struct ath_rx_status *rs, u64 tsf) +{ + u8 sample_buf[SPECTRAL_SAMPLE_MAX_LEN] = {0}; + struct ath_hw *ah = spec_priv->ah; + struct ath_common *common = ath9k_hw_common(spec_priv->ah); + struct ath_softc *sc = common->priv; + u8 num_bins, *vdata = (u8 *)hdr; + struct ath_radar_info *radar_info; + int len = rs->rs_datalen; + int i; + int got_slen = 0; + u8 *sample_start; + int sample_bytes = 0; + int ret = 0; + u16 fft_len, sample_len, freq = ah->curchan->chan->center_freq; + enum nl80211_channel_type chan_type; + ath_cmn_fft_idx_validator *fft_idx_validator; + ath_cmn_fft_sample_handler *fft_handler; + + /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer + * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT + * yet, but this is supposed to be possible as well. + */ + if (rs->rs_phyerr != ATH9K_PHYERR_RADAR && + rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT && + rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) + return 0; + + /* check if spectral scan bit is set. This does not have to be checked + * if received through a SPECTRAL phy error, but shouldn't hurt. + */ + radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; + if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) + return 0; + + if (!spec_priv->rfs_chan_spec_scan) + return 1; + + /* Output buffers are full, no need to process anything + * since there is no space to put the result anyway + */ + ret = ath_cmn_is_fft_buf_full(spec_priv); + if (ret == 1) { + ath_dbg(common, SPECTRAL_SCAN, "FFT report ignored, no space " + "left on output buffers\n"); + return 1; + } + + chan_type = cfg80211_get_chandef_type(&common->hw->conf.chandef); + if ((chan_type == NL80211_CHAN_HT40MINUS) || + (chan_type == NL80211_CHAN_HT40PLUS)) { + fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN; + sample_len = SPECTRAL_HT20_40_SAMPLE_LEN; + num_bins = SPECTRAL_HT20_40_NUM_BINS; + fft_idx_validator = &ath_cmn_max_idx_verify_ht20_40_fft; + fft_handler = &ath_cmn_process_ht20_40_fft; + } else { + fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN; + sample_len = SPECTRAL_HT20_SAMPLE_LEN; + num_bins = SPECTRAL_HT20_NUM_BINS; + fft_idx_validator = ath_cmn_max_idx_verify_ht20_fft; + fft_handler = &ath_cmn_process_ht20_fft; + } + + ath_dbg(common, SPECTRAL_SCAN, "Got radar dump bw_info: 0x%X," + "len: %i fft_len: %i\n", + radar_info->pulse_bw_info, + len, + fft_len); + sample_start = vdata; + for (i = 0; i < len - 2; i++) { + sample_bytes++; + + /* Only a single sample received, no need to look + * for the sample's end, do the correction based + * on the packet's length instead. Note that hw + * will always put the radar_info structure on + * the end. + */ + if (len <= fft_len + 2) { + sample_bytes = len - sizeof(struct ath_radar_info); + got_slen = 1; + } + + /* Search for the end of the FFT frame between + * sample_len - 1 and sample_len + 2. exp_max is 3 + * bits long and it's the only value on the last + * byte of the frame so since it'll be smaller than + * the next byte (the first bin of the next sample) + * 90% of the time, we can use it as a separator. + */ + if (vdata[i] <= 0x7 && sample_bytes >= sample_len - 1) { + + /* Got a frame length within boundaries, there are + * four scenarios here: + * + * a) sample_len -> We got the correct length + * b) sample_len + 2 -> 2 bytes added around bin[31] + * c) sample_len - 1 -> The first byte is missing + * d) sample_len + 1 -> b + c at the same time + * + * When MAC adds 2 extra bytes, bin[31] and bin[32] + * have the same value, so we can use that for further + * verification in cases b and d. + */ + + /* Did we go too far ? If so we couldn't determine + * this sample's boundaries, discard any further + * data + */ + if ((sample_bytes > sample_len + 2) || + ((sample_bytes > sample_len) && + (sample_start[31] != sample_start[32]))) + break; + + /* See if we got a valid frame by checking the + * consistency of mag_info fields. This is to + * prevent from "fixing" a correct frame. + * Failure is non-fatal, later frames may + * be valid. + */ + if (!fft_idx_validator(&vdata[i], i)) { + ath_dbg(common, SPECTRAL_SCAN, + "Found valid fft frame at %i\n", i); + got_slen = 1; + } + + /* We expect 1 - 2 more bytes */ + else if ((sample_start[31] == sample_start[32]) && + (sample_bytes >= sample_len) && + (sample_bytes < sample_len + 2) && + (vdata[i + 1] <= 0x7)) + continue; + + /* Try to distinguish cases a and c */ + else if ((sample_bytes == sample_len - 1) && + (vdata[i + 1] <= 0x7)) + continue; + + got_slen = 1; + } + + if (got_slen) { + ath_dbg(common, SPECTRAL_SCAN, "FFT frame len: %i\n", + sample_bytes); + + /* Only try to fix a frame if it's the only one + * on the report, else just skip it. + */ + if (sample_bytes != sample_len && len <= fft_len + 2) { + ath_cmn_copy_fft_frame(sample_start, + sample_buf, sample_len, + sample_bytes); + + ret = fft_handler(rs, spec_priv, sample_buf, + tsf, freq, chan_type); + + if (ret == 0) + RX_STAT_INC(sc, rx_spectral_sample_good); + else + RX_STAT_INC(sc, rx_spectral_sample_err); + + /* Mix the received bins to the /dev/random + * pool + */ + add_device_randomness(sample_buf, num_bins); + + memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN); + } + + /* Process a normal frame */ + if (sample_bytes == sample_len) { + ret = fft_handler(rs, spec_priv, sample_start, + tsf, freq, chan_type); + + if (ret == 0) + RX_STAT_INC(sc, rx_spectral_sample_good); + else + RX_STAT_INC(sc, rx_spectral_sample_err); + + /* Mix the received bins to the /dev/random + * pool + */ + add_device_randomness(sample_start, num_bins); + } + + /* Short report processed, break out of the + * loop. + */ + if (len <= fft_len + 2) + return 1; + + sample_start = &vdata[i + 1]; + + /* -1 to grab sample_len -1, -2 since + * they 'll get increased by one. In case + * of failure try to recover by going byte + * by byte instead. + */ + if (ret == 0) { + i += num_bins - 2; + sample_bytes = num_bins - 2; + } + got_slen = 0; + } + } + + i -= num_bins - 2; + if (len - i != sizeof(struct ath_radar_info)) + ath_dbg(common, SPECTRAL_SCAN, "FFT report truncated" + "(bytes left: %i)\n", + len - i); + return 1; +} +EXPORT_SYMBOL(ath_cmn_process_fft); + +/*********************/ +/* spectral_scan_ctl */ +/*********************/ + +static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_spec_scan_priv *spec_priv = file->private_data; + char *mode = ""; + unsigned int len; + + switch (spec_priv->spectral_mode) { + case SPECTRAL_DISABLED: + mode = "disable"; + break; + case SPECTRAL_BACKGROUND: + mode = "background"; + break; + case SPECTRAL_CHANSCAN: + mode = "chanscan"; + break; + case SPECTRAL_MANUAL: + mode = "manual"; + break; + } + len = strlen(mode); + return simple_read_from_buffer(user_buf, count, ppos, mode, len); +} + +void ath9k_cmn_spectral_scan_trigger(struct ath_common *common, + struct ath_spec_scan_priv *spec_priv) +{ + struct ath_hw *ah = spec_priv->ah; + u32 rxfilter; + + if (IS_ENABLED(CONFIG_ATH9K_TX99)) + return; + + if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { + ath_err(common, "spectrum analyzer not implemented on this hardware\n"); + return; + } + + if (!spec_priv->spec_config.enabled) + return; + + ath_ps_ops(common)->wakeup(common); + rxfilter = ath9k_hw_getrxfilter(ah); + ath9k_hw_setrxfilter(ah, rxfilter | + ATH9K_RX_FILTER_PHYRADAR | + ATH9K_RX_FILTER_PHYERR); + + /* TODO: usually this should not be necessary, but for some reason + * (or in some mode?) the trigger must be called after the + * configuration, otherwise the register will have its values reset + * (on my ar9220 to value 0x01002310) + */ + ath9k_cmn_spectral_scan_config(common, spec_priv, spec_priv->spectral_mode); + ath9k_hw_ops(ah)->spectral_scan_trigger(ah); + ath_ps_ops(common)->restore(common); +} +EXPORT_SYMBOL(ath9k_cmn_spectral_scan_trigger); + +int ath9k_cmn_spectral_scan_config(struct ath_common *common, + struct ath_spec_scan_priv *spec_priv, + enum spectral_mode spectral_mode) +{ + struct ath_hw *ah = spec_priv->ah; + + if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { + ath_err(common, "spectrum analyzer not implemented on this hardware\n"); + return -1; + } + + switch (spectral_mode) { + case SPECTRAL_DISABLED: + spec_priv->spec_config.enabled = 0; + break; + case SPECTRAL_BACKGROUND: + /* send endless samples. + * TODO: is this really useful for "background"? + */ + spec_priv->spec_config.endless = 1; + spec_priv->spec_config.enabled = 1; + break; + case SPECTRAL_CHANSCAN: + case SPECTRAL_MANUAL: + spec_priv->spec_config.endless = 0; + spec_priv->spec_config.enabled = 1; + break; + default: + return -1; + } + + ath_ps_ops(common)->wakeup(common); + ath9k_hw_ops(ah)->spectral_scan_config(ah, &spec_priv->spec_config); + ath_ps_ops(common)->restore(common); + + spec_priv->spectral_mode = spectral_mode; + + return 0; +} +EXPORT_SYMBOL(ath9k_cmn_spectral_scan_config); + +static ssize_t write_file_spec_scan_ctl(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_spec_scan_priv *spec_priv = file->private_data; + struct ath_common *common = ath9k_hw_common(spec_priv->ah); + char buf[32]; + ssize_t len; + + if (IS_ENABLED(CONFIG_ATH9K_TX99)) + return -EOPNOTSUPP; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + + if (strncmp("trigger", buf, 7) == 0) { + ath9k_cmn_spectral_scan_trigger(common, spec_priv); + } else if (strncmp("background", buf, 10) == 0) { + ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_BACKGROUND); + ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n"); + } else if (strncmp("chanscan", buf, 8) == 0) { + ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_CHANSCAN); + ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n"); + } else if (strncmp("manual", buf, 6) == 0) { + ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_MANUAL); + ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n"); + } else if (strncmp("disable", buf, 7) == 0) { + ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_DISABLED); + ath_dbg(common, CONFIG, "spectral scan: disabled\n"); + } else { + return -EINVAL; + } + + return count; +} + +static const struct file_operations fops_spec_scan_ctl = { + .read = read_file_spec_scan_ctl, + .write = write_file_spec_scan_ctl, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +/*************************/ +/* spectral_short_repeat */ +/*************************/ + +static ssize_t read_file_spectral_short_repeat(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_spec_scan_priv *spec_priv = file->private_data; + char buf[32]; + unsigned int len; + + len = sprintf(buf, "%d\n", spec_priv->spec_config.short_repeat); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_spectral_short_repeat(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_spec_scan_priv *spec_priv = file->private_data; + unsigned long val; + ssize_t ret; + + ret = kstrtoul_from_user(user_buf, count, 0, &val); + if (ret) + return ret; + + if (val > 1) + return -EINVAL; + + spec_priv->spec_config.short_repeat = val; + return count; +} + +static const struct file_operations fops_spectral_short_repeat = { + .read = read_file_spectral_short_repeat, + .write = write_file_spectral_short_repeat, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +/******************/ +/* spectral_count */ +/******************/ + +static ssize_t read_file_spectral_count(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_spec_scan_priv *spec_priv = file->private_data; + char buf[32]; + unsigned int len; + + len = sprintf(buf, "%d\n", spec_priv->spec_config.count); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_spectral_count(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_spec_scan_priv *spec_priv = file->private_data; + unsigned long val; + ssize_t ret; + + ret = kstrtoul_from_user(user_buf, count, 0, &val); + if (ret) + return ret; + if (val > 255) + return -EINVAL; + + spec_priv->spec_config.count = val; + return count; +} + +static const struct file_operations fops_spectral_count = { + .read = read_file_spectral_count, + .write = write_file_spectral_count, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +/*******************/ +/* spectral_period */ +/*******************/ + +static ssize_t read_file_spectral_period(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_spec_scan_priv *spec_priv = file->private_data; + char buf[32]; + unsigned int len; + + len = sprintf(buf, "%d\n", spec_priv->spec_config.period); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_spectral_period(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_spec_scan_priv *spec_priv = file->private_data; + unsigned long val; + ssize_t ret; + + ret = kstrtoul_from_user(user_buf, count, 0, &val); + if (ret) + return ret; + + if (val > 255) + return -EINVAL; + + spec_priv->spec_config.period = val; + return count; +} + +static const struct file_operations fops_spectral_period = { + .read = read_file_spectral_period, + .write = write_file_spectral_period, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +/***********************/ +/* spectral_fft_period */ +/***********************/ + +static ssize_t read_file_spectral_fft_period(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_spec_scan_priv *spec_priv = file->private_data; + char buf[32]; + unsigned int len; + + len = sprintf(buf, "%d\n", spec_priv->spec_config.fft_period); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_spectral_fft_period(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_spec_scan_priv *spec_priv = file->private_data; + unsigned long val; + ssize_t ret; + + ret = kstrtoul_from_user(user_buf, count, 0, &val); + if (ret) + return ret; + + if (val > 15) + return -EINVAL; + + spec_priv->spec_config.fft_period = val; + return count; +} + +static const struct file_operations fops_spectral_fft_period = { + .read = read_file_spectral_fft_period, + .write = write_file_spectral_fft_period, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +/*******************/ +/* Relay interface */ +/*******************/ + +static struct dentry *create_buf_file_handler(const char *filename, + struct dentry *parent, + umode_t mode, + struct rchan_buf *buf, + int *is_global) +{ + struct dentry *buf_file; + + buf_file = debugfs_create_file(filename, mode, parent, buf, + &relay_file_operations); + if (IS_ERR(buf_file)) + return NULL; + + *is_global = 1; + return buf_file; +} + +static int remove_buf_file_handler(struct dentry *dentry) +{ + debugfs_remove(dentry); + + return 0; +} + +static const struct rchan_callbacks rfs_spec_scan_cb = { + .create_buf_file = create_buf_file_handler, + .remove_buf_file = remove_buf_file_handler, +}; + +/*********************/ +/* Debug Init/Deinit */ +/*********************/ + +void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv) +{ + if (spec_priv->rfs_chan_spec_scan) { + relay_close(spec_priv->rfs_chan_spec_scan); + spec_priv->rfs_chan_spec_scan = NULL; + } +} +EXPORT_SYMBOL(ath9k_cmn_spectral_deinit_debug); + +void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, + struct dentry *debugfs_phy) +{ + spec_priv->rfs_chan_spec_scan = relay_open("spectral_scan", + debugfs_phy, + 1024, 256, &rfs_spec_scan_cb, + NULL); + if (!spec_priv->rfs_chan_spec_scan) + return; + + debugfs_create_file("spectral_scan_ctl", + 0600, + debugfs_phy, spec_priv, + &fops_spec_scan_ctl); + debugfs_create_file("spectral_short_repeat", + 0600, + debugfs_phy, spec_priv, + &fops_spectral_short_repeat); + debugfs_create_file("spectral_count", + 0600, + debugfs_phy, spec_priv, + &fops_spectral_count); + debugfs_create_file("spectral_period", + 0600, + debugfs_phy, spec_priv, + &fops_spectral_period); + debugfs_create_file("spectral_fft_period", + 0600, + debugfs_phy, spec_priv, + &fops_spectral_fft_period); +} +EXPORT_SYMBOL(ath9k_cmn_spectral_init_debug); diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.h b/drivers/net/wireless/ath/ath9k/common-spectral.h new file mode 100644 index 000000000000..011d8ab8b974 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/common-spectral.h @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2013 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef SPECTRAL_H +#define SPECTRAL_H + +#include "../spectral_common.h" + +/* enum spectral_mode: + * + * @SPECTRAL_DISABLED: spectral mode is disabled + * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with + * something else. + * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples + * is performed manually. + * @SPECTRAL_CHANSCAN: Like manual, but also triggered when changing channels + * during a channel scan. + */ +enum spectral_mode { + SPECTRAL_DISABLED = 0, + SPECTRAL_BACKGROUND, + SPECTRAL_MANUAL, + SPECTRAL_CHANSCAN, +}; + +#define SPECTRAL_SCAN_BITMASK 0x10 +/* Radar info packet format, used for DFS and spectral formats. */ +struct ath_radar_info { + u8 pulse_length_pri; + u8 pulse_length_ext; + u8 pulse_bw_info; +} __packed; + +/* The HT20 spectral data has 4 bytes of additional information at it's end. + * + * [7:0]: all bins {max_magnitude[1:0], bitmap_weight[5:0]} + * [7:0]: all bins max_magnitude[9:2] + * [7:0]: all bins {max_index[5:0], max_magnitude[11:10]} + * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned) + */ +struct ath_ht20_mag_info { + u8 all_bins[3]; + u8 max_exp; +} __packed; + +/* WARNING: don't actually use this struct! MAC may vary the amount of + * data by -1/+2. This struct is for reference only. + */ +struct ath_ht20_fft_packet { + u8 data[SPECTRAL_HT20_NUM_BINS]; + struct ath_ht20_mag_info mag_info; + struct ath_radar_info radar_info; +} __packed; + +#define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ath_ht20_fft_packet)) +#define SPECTRAL_HT20_SAMPLE_LEN (sizeof(struct ath_ht20_mag_info) +\ + SPECTRAL_HT20_NUM_BINS) + +/* Dynamic 20/40 mode: + * + * [7:0]: lower bins {max_magnitude[1:0], bitmap_weight[5:0]} + * [7:0]: lower bins max_magnitude[9:2] + * [7:0]: lower bins {max_index[5:0], max_magnitude[11:10]} + * [7:0]: upper bins {max_magnitude[1:0], bitmap_weight[5:0]} + * [7:0]: upper bins max_magnitude[9:2] + * [7:0]: upper bins {max_index[5:0], max_magnitude[11:10]} + * [3:0]: max_exp (shift amount to size max bin to 8-bit unsigned) + */ +struct ath_ht20_40_mag_info { + u8 lower_bins[3]; + u8 upper_bins[3]; + u8 max_exp; +} __packed; + +/* WARNING: don't actually use this struct! MAC may vary the amount of + * data. This struct is for reference only. + */ +struct ath_ht20_40_fft_packet { + u8 data[SPECTRAL_HT20_40_NUM_BINS]; + struct ath_ht20_40_mag_info mag_info; + struct ath_radar_info radar_info; +} __packed; + +struct ath_spec_scan_priv { + struct ath_hw *ah; + /* relay(fs) channel for spectral scan */ + struct rchan *rfs_chan_spec_scan; + enum spectral_mode spectral_mode; + struct ath_spec_scan spec_config; +}; + +#define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet)) +#define SPECTRAL_HT20_40_SAMPLE_LEN (sizeof(struct ath_ht20_40_mag_info) +\ + SPECTRAL_HT20_40_NUM_BINS) + +#define SPECTRAL_SAMPLE_MAX_LEN SPECTRAL_HT20_40_SAMPLE_LEN + +/* grabs the max magnitude from the all/upper/lower bins */ +static inline u16 spectral_max_magnitude(u8 *bins) +{ + return (bins[0] & 0xc0) >> 6 | + (bins[1] & 0xff) << 2 | + (bins[2] & 0x03) << 10; +} + +/* return the max magnitude from the all/upper/lower bins */ +static inline u8 spectral_max_index(u8 *bins, int num_bins) +{ + s8 m = (bins[2] & 0xfc) >> 2; + u8 zero_idx = num_bins / 2; + + /* It's a 5 bit signed int, remove its sign and use one's + * complement interpretation to add the sign back to the 8 + * bit int + */ + if (m & 0x20) { + m &= ~0x20; + m |= 0xe0; + } + + /* Bring the zero point to the beginning + * instead of the middle so that we can use + * it for array lookup and that we don't deal + * with negative values later + */ + m += zero_idx; + + /* Sanity check to make sure index is within bounds */ + if (m < 0 || m > num_bins - 1) + m = 0; + + return m; +} + +static inline u8 spectral_max_index_ht40(u8 *bins) +{ + u8 idx; + + idx = spectral_max_index(bins, SPECTRAL_HT20_40_NUM_BINS); + + /* positive values and zero are starting at the beginning + * of the data field. + */ + return idx % (SPECTRAL_HT20_40_NUM_BINS / 2); +} + +static inline u8 spectral_max_index_ht20(u8 *bins) +{ + return spectral_max_index(bins, SPECTRAL_HT20_NUM_BINS); +} + +/* return the bitmap weight from the all/upper/lower bins */ +static inline u8 spectral_bitmap_weight(u8 *bins) +{ + return bins[0] & 0x3f; +} + +#ifdef CONFIG_ATH9K_COMMON_SPECTRAL +void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, struct dentry *debugfs_phy); +void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv); + +void ath9k_cmn_spectral_scan_trigger(struct ath_common *common, + struct ath_spec_scan_priv *spec_priv); +int ath9k_cmn_spectral_scan_config(struct ath_common *common, + struct ath_spec_scan_priv *spec_priv, + enum spectral_mode spectral_mode); +int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_hdr *hdr, + struct ath_rx_status *rs, u64 tsf); +#else +static inline void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, + struct dentry *debugfs_phy) +{ +} + +static inline void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv) +{ +} + +static inline void ath9k_cmn_spectral_scan_trigger(struct ath_common *common, + struct ath_spec_scan_priv *spec_priv) +{ +} + +static inline int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, + struct ieee80211_hdr *hdr, + struct ath_rx_status *rs, u64 tsf) +{ + return 0; +} +#endif /* CONFIG_ATH9K_COMMON_SPECTRAL */ + +#endif /* SPECTRAL_H */ diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 344fdde1d7a3..ffcf2276eb92 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -18,6 +18,7 @@ * Module for common driver code between ath9k and ath9k_htc */ +#include <linux/export.h> #include <linux/kernel.h> #include <linux/module.h> @@ -27,6 +28,251 @@ MODULE_AUTHOR("Atheros Communications"); MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards."); MODULE_LICENSE("Dual BSD/GPL"); +/* Assumes you've already done the endian to CPU conversion */ +bool ath9k_cmn_rx_accept(struct ath_common *common, + struct ieee80211_hdr *hdr, + struct ieee80211_rx_status *rxs, + struct ath_rx_status *rx_stats, + bool *decrypt_error, + unsigned int rxfilter) +{ + struct ath_hw *ah = common->ah; + bool is_mc, is_valid_tkip, strip_mic, mic_error; + __le16 fc; + + fc = hdr->frame_control; + + is_mc = !!is_multicast_ether_addr(hdr->addr1); + is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && + test_bit(rx_stats->rs_keyix, common->tkip_keymap); + strip_mic = is_valid_tkip && ieee80211_is_data(fc) && + ieee80211_has_protected(fc) && + !(rx_stats->rs_status & + (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC | + ATH9K_RXERR_KEYMISS)); + + /* + * Key miss events are only relevant for pairwise keys where the + * descriptor does contain a valid key index. This has been observed + * mostly with CCMP encryption. + */ + if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID || + !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) + rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; + + mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) && + !ieee80211_has_morefrags(fc) && + !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && + (rx_stats->rs_status & ATH9K_RXERR_MIC); + + /* + * The rx_stats->rs_status will not be set until the end of the + * chained descriptors so it can be ignored if rs_more is set. The + * rs_more will be false at the last element of the chained + * descriptors. + */ + if (rx_stats->rs_status != 0) { + u8 status_mask; + + if (rx_stats->rs_status & ATH9K_RXERR_CRC) { + rxs->flag |= RX_FLAG_FAILED_FCS_CRC; + mic_error = false; + } + + if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) || + (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) { + *decrypt_error = true; + mic_error = false; + } + + + /* + * Reject error frames with the exception of + * decryption and MIC failures. For monitor mode, + * we also ignore the CRC error. + */ + status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | + ATH9K_RXERR_KEYMISS; + + if (ah->is_monitoring && (rxfilter & FIF_FCSFAIL)) + status_mask |= ATH9K_RXERR_CRC; + + if (rx_stats->rs_status & ~status_mask) + return false; + } + + /* + * For unicast frames the MIC error bit can have false positives, + * so all MIC error reports need to be validated in software. + * False negatives are not common, so skip software verification + * if the hardware considers the MIC valid. + */ + if (strip_mic) + rxs->flag |= RX_FLAG_MMIC_STRIPPED; + else if (is_mc && mic_error) + rxs->flag |= RX_FLAG_MMIC_ERROR; + + return true; +} +EXPORT_SYMBOL(ath9k_cmn_rx_accept); + +void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, + struct sk_buff *skb, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs, + bool decrypt_error) +{ + struct ath_hw *ah = common->ah; + struct ieee80211_hdr *hdr; + int hdrlen, padpos, padsize; + u8 keyix; + __le16 fc; + + /* see if any padding is done by the hw and remove it */ + hdr = (struct ieee80211_hdr *) skb->data; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + fc = hdr->frame_control; + padpos = ieee80211_hdrlen(fc); + + /* The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = (4 - padpos % 4) % 4; However, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. In addition, we must + * not try to remove padding from short control frames that do + * not have payload. */ + padsize = padpos & 3; + if (padsize && skb->len>=padpos+padsize+FCS_LEN) { + memmove(skb->data + padsize, skb->data, padpos); + skb_pull(skb, padsize); + } + + keyix = rx_stats->rs_keyix; + + if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error && + ieee80211_has_protected(fc)) { + rxs->flag |= RX_FLAG_DECRYPTED; + } else if (ieee80211_has_protected(fc) + && !decrypt_error && skb->len >= hdrlen + 4) { + keyix = skb->data[hdrlen + 3] >> 6; + + if (test_bit(keyix, common->keymap)) + rxs->flag |= RX_FLAG_DECRYPTED; + } + if (ah->sw_mgmt_crypto_rx && + (rxs->flag & RX_FLAG_DECRYPTED) && + ieee80211_is_mgmt(fc)) + /* Use software decrypt for management frames. */ + rxs->flag &= ~RX_FLAG_DECRYPTED; +} +EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess); + +int ath9k_cmn_process_rate(struct ath_common *common, + struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs) +{ + struct ieee80211_supported_band *sband; + enum nl80211_band band; + unsigned int i = 0; + struct ath_hw *ah = common->ah; + + band = ah->curchan->chan->band; + sband = hw->wiphy->bands[band]; + + if (IS_CHAN_QUARTER_RATE(ah->curchan)) + rxs->bw = RATE_INFO_BW_5; + else if (IS_CHAN_HALF_RATE(ah->curchan)) + rxs->bw = RATE_INFO_BW_10; + + if (rx_stats->rs_rate & 0x80) { + /* HT rate */ + rxs->encoding = RX_ENC_HT; + rxs->enc_flags |= rx_stats->enc_flags; + rxs->bw = rx_stats->bw; + rxs->rate_idx = rx_stats->rs_rate & 0x7f; + return 0; + } + + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].hw_value == rx_stats->rs_rate) { + rxs->rate_idx = i; + return 0; + } + if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { + rxs->enc_flags |= RX_ENC_FLAG_SHORTPRE; + rxs->rate_idx = i; + return 0; + } + } + + return -EINVAL; +} +EXPORT_SYMBOL(ath9k_cmn_process_rate); + +void ath9k_cmn_process_rssi(struct ath_common *common, + struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs) +{ + struct ath_hw *ah = common->ah; + int last_rssi; + int rssi = rx_stats->rs_rssi; + int i, j; + + /* + * RSSI is not available for subframes in an A-MPDU. + */ + if (rx_stats->rs_moreaggr) { + rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; + return; + } + + /* + * Check if the RSSI for the last subframe in an A-MPDU + * or an unaggregated frame is valid. + */ + if (rx_stats->rs_rssi == ATH9K_RSSI_BAD) { + rxs->flag |= RX_FLAG_NO_SIGNAL_VAL; + return; + } + + for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) { + s8 rssi; + + if (!(ah->rxchainmask & BIT(i))) + continue; + + rssi = rx_stats->rs_rssi_ctl[i]; + if (rssi != ATH9K_RSSI_BAD) { + rxs->chains |= BIT(j); + rxs->chain_signal[j] = ah->noise + rssi; + } + j++; + } + + /* + * Update Beacon RSSI, this is used by ANI. + */ + if (rx_stats->is_mybeacon && + ((ah->opmode == NL80211_IFTYPE_STATION) || + (ah->opmode == NL80211_IFTYPE_ADHOC))) { + ATH_RSSI_LPF(common->last_rssi, rx_stats->rs_rssi); + last_rssi = common->last_rssi; + + if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) + rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); + if (rssi < 0) + rssi = 0; + + ah->stats.avgbrssi = rssi; + } + + rxs->signal = ah->noise + rx_stats->rs_rssi; +} +EXPORT_SYMBOL(ath9k_cmn_process_rssi); + int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -49,88 +295,62 @@ int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb) } EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype); -static u32 ath9k_get_extchanmode(struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) -{ - u32 chanmode = 0; - - switch (chan->band) { - case IEEE80211_BAND_2GHZ: - switch (channel_type) { - case NL80211_CHAN_NO_HT: - case NL80211_CHAN_HT20: - chanmode = CHANNEL_G_HT20; - break; - case NL80211_CHAN_HT40PLUS: - chanmode = CHANNEL_G_HT40PLUS; - break; - case NL80211_CHAN_HT40MINUS: - chanmode = CHANNEL_G_HT40MINUS; - break; - } - break; - case IEEE80211_BAND_5GHZ: - switch (channel_type) { - case NL80211_CHAN_NO_HT: - case NL80211_CHAN_HT20: - chanmode = CHANNEL_A_HT20; - break; - case NL80211_CHAN_HT40PLUS: - chanmode = CHANNEL_A_HT40PLUS; - break; - case NL80211_CHAN_HT40MINUS: - chanmode = CHANNEL_A_HT40MINUS; - break; - } - break; - default: - break; - } - - return chanmode; -} - /* * Update internal channel flags. */ -void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) +static void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, + struct cfg80211_chan_def *chandef) { + struct ieee80211_channel *chan = chandef->chan; + u16 flags = 0; + ichan->channel = chan->center_freq; ichan->chan = chan; - if (chan->band == IEEE80211_BAND_2GHZ) { - ichan->chanmode = CHANNEL_G; - ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; - } else { - ichan->chanmode = CHANNEL_A; - ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; + if (chan->band == NL80211_BAND_5GHZ) + flags |= CHANNEL_5GHZ; + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_5: + flags |= CHANNEL_QUARTER; + break; + case NL80211_CHAN_WIDTH_10: + flags |= CHANNEL_HALF; + break; + case NL80211_CHAN_WIDTH_20_NOHT: + break; + case NL80211_CHAN_WIDTH_20: + flags |= CHANNEL_HT; + break; + case NL80211_CHAN_WIDTH_40: + if (chandef->center_freq1 > chandef->chan->center_freq) + flags |= CHANNEL_HT40PLUS | CHANNEL_HT; + else + flags |= CHANNEL_HT40MINUS | CHANNEL_HT; + break; + default: + WARN_ON(1); } - if (channel_type != NL80211_CHAN_NO_HT) - ichan->chanmode = ath9k_get_extchanmode(chan, channel_type); + ichan->channelFlags = flags; } -EXPORT_SYMBOL(ath9k_cmn_update_ichannel); /* * Get the internal channel reference. */ -struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, - struct ath_hw *ah) +struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw, + struct ath_hw *ah, + struct cfg80211_chan_def *chandef) { - struct ieee80211_channel *curchan = hw->conf.chandef.chan; + struct ieee80211_channel *curchan = chandef->chan; struct ath9k_channel *channel; - u8 chan_idx; - chan_idx = curchan->hw_value; - channel = &ah->channels[chan_idx]; - ath9k_cmn_update_ichannel(channel, curchan, - cfg80211_get_chandef_type(&hw->conf.chandef)); + channel = &ah->channels[curchan->hw_value]; + ath9k_cmn_update_ichannel(channel, chandef); return channel; } -EXPORT_SYMBOL(ath9k_cmn_get_curchannel); +EXPORT_SYMBOL(ath9k_cmn_get_channel); int ath9k_cmn_count_streams(unsigned int chainmask, int max) { @@ -150,11 +370,11 @@ void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, { struct ath_regulatory *reg = ath9k_hw_regulatory(ah); - if (reg->power_limit != new_txpow) { + if (ah->curchan && reg->power_limit != new_txpow) ath9k_hw_set_txpowerlimit(ah, new_txpow, false); - /* read back in case value is clamped */ - *txpower = reg->max_power_level; - } + + /* read back in case value is clamped */ + *txpower = reg->max_power_level; } EXPORT_SYMBOL(ath9k_cmn_update_txpow); diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 207d06995b15..12204cf86fcf 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -21,6 +21,11 @@ #include "hw.h" #include "hw-ops.h" +#include "common-init.h" +#include "common-beacon.h" +#include "common-debug.h" +#include "common-spectral.h" + /* Common header for Atheros 802.11n base driver cores */ #define WME_BA_BMP_SIZE 64 @@ -42,15 +47,44 @@ #define ATH_EP_RND(x, mul) \ (((x) + ((mul)/2)) / (mul)) +#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) + +struct ath_beacon_config { + struct ieee80211_vif *main_vif; + int beacon_interval; + u16 dtim_period; + u16 bmiss_timeout; + u8 dtim_count; + u8 enable_beacon; + bool ibss_creator; + u32 nexttbtt; + u32 intval; +}; + +bool ath9k_cmn_rx_accept(struct ath_common *common, + struct ieee80211_hdr *hdr, + struct ieee80211_rx_status *rxs, + struct ath_rx_status *rx_stats, + bool *decrypt_error, + unsigned int rxfilter); +void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, + struct sk_buff *skb, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs, + bool decrypt_error); +int ath9k_cmn_process_rate(struct ath_common *common, + struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs); +void ath9k_cmn_process_rssi(struct ath_common *common, + struct ieee80211_hw *hw, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rxs); int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb); -void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type); -struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, - struct ath_hw *ah); +struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw, + struct ath_hw *ah, + struct cfg80211_chan_def *chandef); int ath9k_cmn_count_streams(unsigned int chainmask, int max); -void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common, - enum ath_stomp_type stomp_type); void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, u16 new_txpow, u16 *txpower); void ath9k_cmn_init_crypto(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 87454f6c7b4f..74a0134075cf 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -17,8 +17,7 @@ #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/export.h> -#include <linux/relay.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include "ath9k.h" @@ -27,6 +26,47 @@ #define REG_READ_D(_ah, _reg) \ ath9k_hw_common(_ah)->ops->read((_ah), (_reg)) +void ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause) +{ + if (sync_cause) + sc->debug.stats.istats.sync_cause_all++; + if (sync_cause & AR_INTR_SYNC_RTC_IRQ) + sc->debug.stats.istats.sync_rtc_irq++; + if (sync_cause & AR_INTR_SYNC_MAC_IRQ) + sc->debug.stats.istats.sync_mac_irq++; + if (sync_cause & AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS) + sc->debug.stats.istats.eeprom_illegal_access++; + if (sync_cause & AR_INTR_SYNC_APB_TIMEOUT) + sc->debug.stats.istats.apb_timeout++; + if (sync_cause & AR_INTR_SYNC_PCI_MODE_CONFLICT) + sc->debug.stats.istats.pci_mode_conflict++; + if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) + sc->debug.stats.istats.host1_fatal++; + if (sync_cause & AR_INTR_SYNC_HOST1_PERR) + sc->debug.stats.istats.host1_perr++; + if (sync_cause & AR_INTR_SYNC_TRCV_FIFO_PERR) + sc->debug.stats.istats.trcv_fifo_perr++; + if (sync_cause & AR_INTR_SYNC_RADM_CPL_EP) + sc->debug.stats.istats.radm_cpl_ep++; + if (sync_cause & AR_INTR_SYNC_RADM_CPL_DLLP_ABORT) + sc->debug.stats.istats.radm_cpl_dllp_abort++; + if (sync_cause & AR_INTR_SYNC_RADM_CPL_TLP_ABORT) + sc->debug.stats.istats.radm_cpl_tlp_abort++; + if (sync_cause & AR_INTR_SYNC_RADM_CPL_ECRC_ERR) + sc->debug.stats.istats.radm_cpl_ecrc_err++; + if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) + sc->debug.stats.istats.radm_cpl_timeout++; + if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) + sc->debug.stats.istats.local_timeout++; + if (sync_cause & AR_INTR_SYNC_PM_ACCESS) + sc->debug.stats.istats.pm_access++; + if (sync_cause & AR_INTR_SYNC_MAC_AWAKE) + sc->debug.stats.istats.mac_awake++; + if (sync_cause & AR_INTR_SYNC_MAC_ASLEEP) + sc->debug.stats.istats.mac_asleep++; + if (sync_cause & AR_INTR_SYNC_MAC_SLEEP_ACCESS) + sc->debug.stats.istats.mac_sleep_access++; +} static ssize_t ath9k_debugfs_read_buf(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -56,21 +96,16 @@ static ssize_t read_file_debug(struct file *file, char __user *user_buf, } static ssize_t write_file_debug(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); unsigned long mask; - char buf[32]; - ssize_t len; + ssize_t ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, &mask)) - return -EINVAL; + ret = kstrtoul_from_user(user_buf, count, 0, &mask); + if (ret) + return ret; common->debug_mask = mask; return count; @@ -88,90 +123,6 @@ static const struct file_operations fops_debug = { #define DMA_BUF_LEN 1024 -static ssize_t read_file_tx_chainmask(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - struct ath_hw *ah = sc->sc_ah; - char buf[32]; - unsigned int len; - - len = sprintf(buf, "0x%08x\n", ah->txchainmask); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_tx_chainmask(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - struct ath_hw *ah = sc->sc_ah; - unsigned long mask; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, &mask)) - return -EINVAL; - - ah->txchainmask = mask; - ah->caps.tx_chainmask = mask; - return count; -} - -static const struct file_operations fops_tx_chainmask = { - .read = read_file_tx_chainmask, - .write = write_file_tx_chainmask, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - - -static ssize_t read_file_rx_chainmask(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - struct ath_hw *ah = sc->sc_ah; - char buf[32]; - unsigned int len; - - len = sprintf(buf, "0x%08x\n", ah->rxchainmask); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_rx_chainmask(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - struct ath_hw *ah = sc->sc_ah; - unsigned long mask; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, &mask)) - return -EINVAL; - - ah->rxchainmask = mask; - ah->caps.rx_chainmask = mask; - return count; -} - -static const struct file_operations fops_rx_chainmask = { - .read = read_file_rx_chainmask, - .write = write_file_rx_chainmask, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; static ssize_t read_file_ani(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -179,46 +130,45 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_hw *ah = sc->sc_ah; - unsigned int len = 0, size = 1024; + unsigned int len = 0; + const unsigned int size = 1024; ssize_t retval = 0; char *buf; + int i; + struct { + const char *name; + unsigned int val; + } ani_info[] = { + { "ANI RESET", ah->stats.ast_ani_reset }, + { "OFDM LEVEL", ah->ani.ofdmNoiseImmunityLevel }, + { "CCK LEVEL", ah->ani.cckNoiseImmunityLevel }, + { "SPUR UP", ah->stats.ast_ani_spurup }, + { "SPUR DOWN", ah->stats.ast_ani_spurdown }, + { "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon }, + { "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff }, + { "MRC-CCK ON", ah->stats.ast_ani_ccklow }, + { "MRC-CCK OFF", ah->stats.ast_ani_cckhigh }, + { "FIR-STEP UP", ah->stats.ast_ani_stepup }, + { "FIR-STEP DOWN", ah->stats.ast_ani_stepdown }, + { "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero }, + { "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs }, + { "CCK ERRORS", ah->stats.ast_ani_cckerrs }, + }; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - if (common->disable_ani) { - len += snprintf(buf + len, size - len, "%s: %s\n", - "ANI", "DISABLED"); + len += scnprintf(buf + len, size - len, "%15s: %s\n", "ANI", + common->disable_ani ? "DISABLED" : "ENABLED"); + + if (common->disable_ani) goto exit; - } - len += snprintf(buf + len, size - len, "%15s: %s\n", - "ANI", "ENABLED"); - len += snprintf(buf + len, size - len, "%15s: %u\n", - "ANI RESET", ah->stats.ast_ani_reset); - len += snprintf(buf + len, size - len, "%15s: %u\n", - "SPUR UP", ah->stats.ast_ani_spurup); - len += snprintf(buf + len, size - len, "%15s: %u\n", - "SPUR DOWN", ah->stats.ast_ani_spurup); - len += snprintf(buf + len, size - len, "%15s: %u\n", - "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon); - len += snprintf(buf + len, size - len, "%15s: %u\n", - "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff); - len += snprintf(buf + len, size - len, "%15s: %u\n", - "MRC-CCK ON", ah->stats.ast_ani_ccklow); - len += snprintf(buf + len, size - len, "%15s: %u\n", - "MRC-CCK OFF", ah->stats.ast_ani_cckhigh); - len += snprintf(buf + len, size - len, "%15s: %u\n", - "FIR-STEP UP", ah->stats.ast_ani_stepup); - len += snprintf(buf + len, size - len, "%15s: %u\n", - "FIR-STEP DOWN", ah->stats.ast_ani_stepdown); - len += snprintf(buf + len, size - len, "%15s: %u\n", - "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero); - len += snprintf(buf + len, size - len, "%15s: %u\n", - "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs); - len += snprintf(buf + len, size - len, "%15s: %u\n", - "CCK ERRORS", ah->stats.ast_ani_cckerrs); + for (i = 0; i < ARRAY_SIZE(ani_info); i++) + len += scnprintf(buf + len, size - len, "%15s: %u\n", + ani_info[i].name, ani_info[i].val); + exit: if (len > size) len = size; @@ -236,24 +186,19 @@ static ssize_t write_file_ani(struct file *file, struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); unsigned long ani; - char buf[32]; - ssize_t len; + ssize_t ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; + ret = kstrtoul_from_user(user_buf, count, 0, &ani); + if (ret) + return ret; - buf[len] = '\0'; - if (kstrtoul(buf, 0, &ani)) - return -EINVAL; - - if (ani < 0 || ani > 1) + if (ani > 1) return -EINVAL; common->disable_ani = !ani; if (common->disable_ani) { - clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); + clear_bit(ATH_OP_ANI_RUN, &common->op_flags); ath_stop_ani(sc); } else { ath_check_ani(sc); @@ -270,73 +215,186 @@ static const struct file_operations fops_ani = { .llseek = default_llseek, }; -static ssize_t read_file_ant_diversity(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + +static ssize_t read_file_bt_ant_diversity(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); char buf[32]; unsigned int len; - len = sprintf(buf, "%d\n", common->antenna_diversity); + len = sprintf(buf, "%d\n", common->bt_ant_diversity); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -static ssize_t write_file_ant_diversity(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t write_file_bt_ant_diversity(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - unsigned long antenna_diversity; - char buf[32]; - ssize_t len; + struct ath9k_hw_capabilities *pCap = &sc->sc_ah->caps; + unsigned long bt_ant_diversity; + ssize_t ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; + ret = kstrtoul_from_user(user_buf, count, 0, &bt_ant_diversity); + if (ret) + return ret; - if (!AR_SREV_9565(sc->sc_ah)) + if (!(pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV)) goto exit; - buf[len] = '\0'; - if (kstrtoul(buf, 0, &antenna_diversity)) - return -EINVAL; - - common->antenna_diversity = !!antenna_diversity; + common->bt_ant_diversity = !!bt_ant_diversity; ath9k_ps_wakeup(sc); - ath_ant_comb_update(sc); - ath_dbg(common, CONFIG, "Antenna diversity: %d\n", - common->antenna_diversity); + ath9k_hw_set_bt_ant_diversity(sc->sc_ah, common->bt_ant_diversity); + ath_dbg(common, CONFIG, "Enable WLAN/BT RX Antenna diversity: %d\n", + common->bt_ant_diversity); ath9k_ps_restore(sc); exit: return count; } -static const struct file_operations fops_ant_diversity = { - .read = read_file_ant_diversity, - .write = write_file_ant_diversity, +static const struct file_operations fops_bt_ant_diversity = { + .read = read_file_bt_ant_diversity, + .write = write_file_bt_ant_diversity, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; -static ssize_t read_file_dma(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +#endif + +void ath9k_debug_stat_ant(struct ath_softc *sc, + struct ath_hw_antcomb_conf *div_ant_conf, + int main_rssi_avg, int alt_rssi_avg) +{ + struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN]; + struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT]; + + as_main->lna_attempt_cnt[div_ant_conf->main_lna_conf]++; + as_alt->lna_attempt_cnt[div_ant_conf->alt_lna_conf]++; + + as_main->rssi_avg = main_rssi_avg; + as_alt->rssi_avg = alt_rssi_avg; +} + +static ssize_t read_file_antenna_diversity(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_hw *ah = sc->sc_ah; - char *buf; - int retval; + struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_antenna_stats *as_main = &sc->debug.stats.ant_stats[ANT_MAIN]; + struct ath_antenna_stats *as_alt = &sc->debug.stats.ant_stats[ANT_ALT]; + struct ath_hw_antcomb_conf div_ant_conf; unsigned int len = 0; + const unsigned int size = 1024; + ssize_t retval = 0; + char *buf; + static const char *lna_conf_str[4] = { + "LNA1_MINUS_LNA2", "LNA2", "LNA1", "LNA1_PLUS_LNA2" + }; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + if (!(pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)) { + len += scnprintf(buf + len, size - len, "%s\n", + "Antenna Diversity Combining is disabled"); + goto exit; + } + + ath9k_ps_wakeup(sc); + ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf); + len += scnprintf(buf + len, size - len, "Current MAIN config : %s\n", + lna_conf_str[div_ant_conf.main_lna_conf]); + len += scnprintf(buf + len, size - len, "Current ALT config : %s\n", + lna_conf_str[div_ant_conf.alt_lna_conf]); + len += scnprintf(buf + len, size - len, "Average MAIN RSSI : %d\n", + as_main->rssi_avg); + len += scnprintf(buf + len, size - len, "Average ALT RSSI : %d\n\n", + as_alt->rssi_avg); + ath9k_ps_restore(sc); + + len += scnprintf(buf + len, size - len, "Packet Receive Cnt:\n"); + len += scnprintf(buf + len, size - len, "-------------------\n"); + + len += scnprintf(buf + len, size - len, "%30s%15s\n", + "MAIN", "ALT"); + len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", + "TOTAL COUNT", + as_main->recv_cnt, + as_alt->recv_cnt); + len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", + "LNA1", + as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1], + as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1]); + len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", + "LNA2", + as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2], + as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2]); + len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", + "LNA1 + LNA2", + as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2], + as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]); + len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", + "LNA1 - LNA2", + as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2], + as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]); + + len += scnprintf(buf + len, size - len, "\nLNA Config Attempts:\n"); + len += scnprintf(buf + len, size - len, "--------------------\n"); + + len += scnprintf(buf + len, size - len, "%30s%15s\n", + "MAIN", "ALT"); + len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", + "LNA1", + as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1], + as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1]); + len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", + "LNA2", + as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2], + as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2]); + len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", + "LNA1 + LNA2", + as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2], + as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]); + len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n", + "LNA1 - LNA2", + as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2], + as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]); + +exit: + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_antenna_diversity = { + .read = read_file_antenna_diversity, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static int read_file_dma(struct seq_file *file, void *data) +{ + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; int i, qcuOffset = 0, dcuOffset = 0; u32 *qcuBase = &val[0], *dcuBase = &val[4]; - buf = kmalloc(DMA_BUF_LEN, GFP_KERNEL); - if (!buf) - return -ENOMEM; - ath9k_ps_wakeup(sc); REG_WRITE_D(ah, AR_MACMISC, @@ -344,21 +402,18 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, (AR_MACMISC_MISC_OBS_BUS_1 << AR_MACMISC_MISC_OBS_BUS_MSB_S))); - len += snprintf(buf + len, DMA_BUF_LEN - len, - "Raw DMA Debug values:\n"); + seq_puts(file, "Raw DMA Debug values:\n"); for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { if (i % 4 == 0) - len += snprintf(buf + len, DMA_BUF_LEN - len, "\n"); + seq_puts(file, "\n"); val[i] = REG_READ_D(ah, AR_DMADBG_0 + (i * sizeof(u32))); - len += snprintf(buf + len, DMA_BUF_LEN - len, "%d: %08x ", - i, val[i]); + seq_printf(file, "%d: %08x ", i, val[i]); } - len += snprintf(buf + len, DMA_BUF_LEN - len, "\n\n"); - len += snprintf(buf + len, DMA_BUF_LEN - len, - "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); + seq_puts(file, "\n\n"); + seq_puts(file, "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) { if (i == 8) { @@ -371,57 +426,35 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf, dcuBase++; } - len += snprintf(buf + len, DMA_BUF_LEN - len, - "%2d %2x %1x %2x %2x\n", - i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, - (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), - val[2] & (0x7 << (i * 3)) >> (i * 3), - (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); + seq_printf(file, "%2d %2x %1x %2x %2x\n", + i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, + (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), + (val[2] & (0x7 << (i * 3))) >> (i * 3), + (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); } - len += snprintf(buf + len, DMA_BUF_LEN - len, "\n"); - - len += snprintf(buf + len, DMA_BUF_LEN - len, - "qcu_stitch state: %2x qcu_fetch state: %2x\n", - (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); - len += snprintf(buf + len, DMA_BUF_LEN - len, - "qcu_complete state: %2x dcu_complete state: %2x\n", - (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); - len += snprintf(buf + len, DMA_BUF_LEN - len, - "dcu_arb state: %2x dcu_fp state: %2x\n", - (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); - len += snprintf(buf + len, DMA_BUF_LEN - len, - "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", - (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); - len += snprintf(buf + len, DMA_BUF_LEN - len, - "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", - (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); - len += snprintf(buf + len, DMA_BUF_LEN - len, - "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", - (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); - - len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x\n", - REG_READ_D(ah, AR_OBS_BUS_1)); - len += snprintf(buf + len, DMA_BUF_LEN - len, - "AR_CR: 0x%x\n", REG_READ_D(ah, AR_CR)); + seq_puts(file, "\n"); - ath9k_ps_restore(sc); + seq_printf(file, "qcu_stitch state: %2x qcu_fetch state: %2x\n", + (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); + seq_printf(file, "qcu_complete state: %2x dcu_complete state: %2x\n", + (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); + seq_printf(file, "dcu_arb state: %2x dcu_fp state: %2x\n", + (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); + seq_printf(file, "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", + (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); + seq_printf(file, "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", + (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); + seq_printf(file, "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", + (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); - if (len > DMA_BUF_LEN) - len = DMA_BUF_LEN; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return retval; -} + seq_printf(file, "pcu observe: 0x%x\n", REG_READ_D(ah, AR_OBS_BUS_1)); + seq_printf(file, "AR_CR: 0x%x\n", REG_READ_D(ah, AR_CR)); -static const struct file_operations fops_dma = { - .read = read_file_dma, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; + ath9k_ps_restore(sc); + return 0; +} void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) { @@ -476,28 +509,21 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) sc->debug.stats.istats.gen_timer++; } -static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static int read_file_interrupt(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private_data; - unsigned int len = 0; - int rv; - int mxlen = 4000; - char *buf = kmalloc(mxlen, GFP_KERNEL); - if (!buf) - return -ENOMEM; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; #define PR_IS(a, s) \ do { \ - len += snprintf(buf + len, mxlen - len, \ - "%21s: %10u\n", a, \ - sc->debug.stats.istats.s); \ + seq_printf(file, "%21s: %10u\n", a, \ + sc->debug.stats.istats.s); \ } while (0) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { PR_IS("RXLP", rxlp); PR_IS("RXHP", rxhp); - PR_IS("WATHDOG", bb_watchdog); + PR_IS("WATCHDOG", bb_watchdog); } else { PR_IS("RX", rxok); } @@ -522,8 +548,7 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, PR_IS("GENTIMER", gen_timer); PR_IS("TOTAL", total); - len += snprintf(buf + len, mxlen - len, - "SYNC_CAUSE stats:\n"); + seq_puts(file, "SYNC_CAUSE stats:\n"); PR_IS("Sync-All", sync_cause_all); PR_IS("RTC-IRQ", sync_rtc_irq); @@ -545,42 +570,21 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, PR_IS("MAC-Asleep", mac_asleep); PR_IS("MAC-Sleep-Access", mac_sleep_access); - if (len > mxlen) - len = mxlen; - - rv = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return rv; + return 0; } -static const struct file_operations fops_interrupt = { - .read = read_file_interrupt, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_xmit(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static int read_file_xmit(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private_data; - char *buf; - unsigned int len = 0, size = 2048; - ssize_t retval = 0; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; - len += sprintf(buf, "%30s %10s%10s%10s\n\n", - "BE", "BK", "VI", "VO"); + seq_printf(file, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO"); PR("MPDUs Queued: ", queued); PR("MPDUs Completed: ", completed); PR("MPDUs XRetried: ", xretries); PR("Aggregates: ", a_aggr); PR("AMPDUs Queued HW:", a_queued_hw); - PR("AMPDUs Queued SW:", a_queued_sw); PR("AMPDUs Completed:", a_completed); PR("AMPDUs Retried: ", a_retries); PR("AMPDUs XRetried: ", a_xretries); @@ -598,656 +602,257 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, PR("HW-tx-proc-desc: ", txprocdesc); PR("TX-Failed: ", txfailed); - if (len > size) - len = size; + return 0; +} - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); +static void print_queue(struct ath_softc *sc, struct ath_txq *txq, + struct seq_file *file) +{ + ath_txq_lock(sc, txq); - return retval; + seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum); + seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth); + seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth); + seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames); + + ath_txq_unlock(sc, txq); } -static ssize_t read_file_queues(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static int read_file_queues(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private_data; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; struct ath_txq *txq; - char *buf; - unsigned int len = 0, size = 1024; - ssize_t retval = 0; int i; - char *qname[4] = {"VO", "VI", "BE", "BK"}; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; + static const char *qname[4] = { + "VO", "VI", "BE", "BK" + }; for (i = 0; i < IEEE80211_NUM_ACS; i++) { txq = sc->tx.txq_map[i]; - len += snprintf(buf + len, size - len, "(%s): ", qname[i]); - - ath_txq_lock(sc, txq); - - len += snprintf(buf + len, size - len, "%s: %d ", - "qnum", txq->axq_qnum); - len += snprintf(buf + len, size - len, "%s: %2d ", - "qdepth", txq->axq_depth); - len += snprintf(buf + len, size - len, "%s: %2d ", - "ampdu-depth", txq->axq_ampdu_depth); - len += snprintf(buf + len, size - len, "%s: %3d ", - "pending", txq->pending_frames); - len += snprintf(buf + len, size - len, "%s: %d\n", - "stopped", txq->stopped); - - ath_txq_unlock(sc, txq); + seq_printf(file, "(%s): ", qname[i]); + print_queue(sc, txq, file); } - if (len > size) - len = size; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); + seq_puts(file, "(CAB): "); + print_queue(sc, sc->beacon.cabq, file); - return retval; + return 0; } -static ssize_t read_file_misc(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static int read_file_misc(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private_data; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ieee80211_hw *hw = sc->hw; struct ath9k_vif_iter_data iter_data; - char buf[512]; - unsigned int len = 0; - ssize_t retval = 0; + struct ath_chanctx *ctx; unsigned int reg; - u32 rxfilter; + u32 rxfilter, i; - len += snprintf(buf + len, sizeof(buf) - len, - "BSSID: %pM\n", common->curbssid); - len += snprintf(buf + len, sizeof(buf) - len, - "BSSID-MASK: %pM\n", common->bssidmask); - len += snprintf(buf + len, sizeof(buf) - len, - "OPMODE: %s\n", ath_opmode_to_string(sc->sc_ah->opmode)); + seq_printf(file, "BSSID: %pM\n", common->curbssid); + seq_printf(file, "BSSID-MASK: %pM\n", common->bssidmask); + seq_printf(file, "OPMODE: %s\n", + ath_opmode_to_string(sc->sc_ah->opmode)); ath9k_ps_wakeup(sc); rxfilter = ath9k_hw_getrxfilter(sc->sc_ah); ath9k_ps_restore(sc); - len += snprintf(buf + len, sizeof(buf) - len, - "RXFILTER: 0x%x", rxfilter); + seq_printf(file, "RXFILTER: 0x%x", rxfilter); if (rxfilter & ATH9K_RX_FILTER_UCAST) - len += snprintf(buf + len, sizeof(buf) - len, " UCAST"); + seq_puts(file, " UCAST"); if (rxfilter & ATH9K_RX_FILTER_MCAST) - len += snprintf(buf + len, sizeof(buf) - len, " MCAST"); + seq_puts(file, " MCAST"); if (rxfilter & ATH9K_RX_FILTER_BCAST) - len += snprintf(buf + len, sizeof(buf) - len, " BCAST"); + seq_puts(file, " BCAST"); if (rxfilter & ATH9K_RX_FILTER_CONTROL) - len += snprintf(buf + len, sizeof(buf) - len, " CONTROL"); + seq_puts(file, " CONTROL"); if (rxfilter & ATH9K_RX_FILTER_BEACON) - len += snprintf(buf + len, sizeof(buf) - len, " BEACON"); + seq_puts(file, " BEACON"); if (rxfilter & ATH9K_RX_FILTER_PROM) - len += snprintf(buf + len, sizeof(buf) - len, " PROM"); + seq_puts(file, " PROM"); if (rxfilter & ATH9K_RX_FILTER_PROBEREQ) - len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ"); + seq_puts(file, " PROBEREQ"); if (rxfilter & ATH9K_RX_FILTER_PHYERR) - len += snprintf(buf + len, sizeof(buf) - len, " PHYERR"); + seq_puts(file, " PHYERR"); if (rxfilter & ATH9K_RX_FILTER_MYBEACON) - len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON"); + seq_puts(file, " MYBEACON"); if (rxfilter & ATH9K_RX_FILTER_COMP_BAR) - len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR"); + seq_puts(file, " COMP_BAR"); if (rxfilter & ATH9K_RX_FILTER_PSPOLL) - len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL"); + seq_puts(file, " PSPOLL"); if (rxfilter & ATH9K_RX_FILTER_PHYRADAR) - len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR"); + seq_puts(file, " PHYRADAR"); if (rxfilter & ATH9K_RX_FILTER_MCAST_BCAST_ALL) - len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL"); + seq_puts(file, " MCAST_BCAST_ALL"); if (rxfilter & ATH9K_RX_FILTER_CONTROL_WRAPPER) - len += snprintf(buf + len, sizeof(buf) - len, " CONTROL_WRAPPER"); + seq_puts(file, " CONTROL_WRAPPER"); - len += snprintf(buf + len, sizeof(buf) - len, "\n"); + seq_puts(file, "\n"); reg = sc->sc_ah->imask; - len += snprintf(buf + len, sizeof(buf) - len, "INTERRUPT-MASK: 0x%x", reg); + seq_printf(file, "INTERRUPT-MASK: 0x%x", reg); if (reg & ATH9K_INT_SWBA) - len += snprintf(buf + len, sizeof(buf) - len, " SWBA"); + seq_puts(file, " SWBA"); if (reg & ATH9K_INT_BMISS) - len += snprintf(buf + len, sizeof(buf) - len, " BMISS"); + seq_puts(file, " BMISS"); if (reg & ATH9K_INT_CST) - len += snprintf(buf + len, sizeof(buf) - len, " CST"); + seq_puts(file, " CST"); if (reg & ATH9K_INT_RX) - len += snprintf(buf + len, sizeof(buf) - len, " RX"); + seq_puts(file, " RX"); if (reg & ATH9K_INT_RXHP) - len += snprintf(buf + len, sizeof(buf) - len, " RXHP"); + seq_puts(file, " RXHP"); if (reg & ATH9K_INT_RXLP) - len += snprintf(buf + len, sizeof(buf) - len, " RXLP"); + seq_puts(file, " RXLP"); if (reg & ATH9K_INT_BB_WATCHDOG) - len += snprintf(buf + len, sizeof(buf) - len, " BB_WATCHDOG"); + seq_puts(file, " BB_WATCHDOG"); - len += snprintf(buf + len, sizeof(buf) - len, "\n"); + seq_puts(file, "\n"); - ath9k_calculate_iter_data(hw, NULL, &iter_data); + i = 0; + ath_for_each_chanctx(sc, ctx) { + if (list_empty(&ctx->vifs)) + continue; + ath9k_calculate_iter_data(sc, ctx, &iter_data); + + seq_printf(file, + "VIFS: CTX %i(%i) AP: %i STA: %i MESH: %i", + i++, (int)(ctx->assigned), iter_data.naps, + iter_data.nstations, + iter_data.nmeshes); + seq_printf(file, " ADHOC: %i OCB: %i TOTAL: %hi BEACON-VIF: %hi\n", + iter_data.nadhocs, iter_data.nocbs, sc->cur_chan->nvifs, + sc->nbcnvifs); + } - len += snprintf(buf + len, sizeof(buf) - len, - "VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i" - " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n", - iter_data.naps, iter_data.nstations, iter_data.nmeshes, - iter_data.nwds, iter_data.nadhocs, - sc->nvifs, sc->nbcnvifs); + return 0; +} - if (len > sizeof(buf)) - len = sizeof(buf); +static int read_file_reset(struct seq_file *file, void *data) +{ + struct ath_softc *sc = file->private; + static const char * const reset_cause[__RESET_TYPE_MAX] = { + [RESET_TYPE_USER] = "User reset", + [RESET_TYPE_BB_HANG] = "Baseband Hang", + [RESET_TYPE_BB_WATCHDOG] = "Baseband Watchdog", + [RESET_TYPE_FATAL_INT] = "Fatal HW Error", + [RESET_TYPE_TX_ERROR] = "TX HW error", + [RESET_TYPE_TX_GTT] = "Transmit timeout", + [RESET_TYPE_TX_HANG] = "TX Path Hang", + [RESET_TYPE_PLL_HANG] = "PLL RX Hang", + [RESET_TYPE_MAC_HANG] = "MAC Hang", + [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon", + [RESET_TYPE_MCI] = "MCI Reset", + [RESET_TYPE_CALIBRATION] = "Calibration error", + [RESET_TX_DMA_ERROR] = "Tx DMA stop error", + [RESET_RX_DMA_ERROR] = "Rx DMA stop error", + [RESET_TYPE_RX_INACTIVE] = "Rx path inactive", + }; + int i; - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - return retval; + for (i = 0; i < ARRAY_SIZE(reset_cause); i++) { + if (!reset_cause[i]) + continue; + + seq_printf(file, "%17s: %2d\n", reset_cause[i], + sc->debug.stats.reset[i]); + } + + return 0; } -static ssize_t read_file_reset(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static int open_file_reset(struct inode *inode, struct file *f) { - struct ath_softc *sc = file->private_data; - char buf[512]; - unsigned int len = 0; + return single_open(f, read_file_reset, inode->i_private); +} + +static ssize_t write_file_reset(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file_inode(file)->i_private; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + unsigned long val; + ssize_t ret; - len += snprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "Baseband Hang", - sc->debug.stats.reset[RESET_TYPE_BB_HANG]); - len += snprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "Baseband Watchdog", - sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG]); - len += snprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "Fatal HW Error", - sc->debug.stats.reset[RESET_TYPE_FATAL_INT]); - len += snprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "TX HW error", - sc->debug.stats.reset[RESET_TYPE_TX_ERROR]); - len += snprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "TX Path Hang", - sc->debug.stats.reset[RESET_TYPE_TX_HANG]); - len += snprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "PLL RX Hang", - sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); - len += snprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "MCI Reset", - sc->debug.stats.reset[RESET_TYPE_MCI]); - - if (len > sizeof(buf)) - len = sizeof(buf); + ret = kstrtoul_from_user(user_buf, count, 0, &val); + if (ret) + return ret; - return simple_read_from_buffer(user_buf, count, ppos, buf, len); + if (val != 1) + return -EINVAL; + + /* avoid rearming hw_reset_work on shutdown */ + mutex_lock(&sc->mutex); + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { + mutex_unlock(&sc->mutex); + return -EBUSY; + } + + ath9k_queue_reset(sc, RESET_TYPE_USER); + mutex_unlock(&sc->mutex); + + return count; } +static const struct file_operations fops_reset = { + .read = seq_read, + .write = write_file_reset, + .open = open_file_reset, + .owner = THIS_MODULE, + .llseek = seq_lseek, + .release = single_release, +}; + void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, struct ath_txq *txq, unsigned int flags) { int qnum = txq->axq_qnum; - TX_STAT_INC(qnum, tx_pkts_all); + TX_STAT_INC(sc, qnum, tx_pkts_all); sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len; if (bf_isampdu(bf)) { if (flags & ATH_TX_ERROR) - TX_STAT_INC(qnum, a_xretries); + TX_STAT_INC(sc, qnum, a_xretries); else - TX_STAT_INC(qnum, a_completed); + TX_STAT_INC(sc, qnum, a_completed); } else { if (ts->ts_status & ATH9K_TXERR_XRETRY) - TX_STAT_INC(qnum, xretries); + TX_STAT_INC(sc, qnum, xretries); else - TX_STAT_INC(qnum, completed); + TX_STAT_INC(sc, qnum, completed); } if (ts->ts_status & ATH9K_TXERR_FILT) - TX_STAT_INC(qnum, txerr_filtered); + TX_STAT_INC(sc, qnum, txerr_filtered); if (ts->ts_status & ATH9K_TXERR_FIFO) - TX_STAT_INC(qnum, fifo_underrun); + TX_STAT_INC(sc, qnum, fifo_underrun); if (ts->ts_status & ATH9K_TXERR_XTXOP) - TX_STAT_INC(qnum, xtxop); + TX_STAT_INC(sc, qnum, xtxop); if (ts->ts_status & ATH9K_TXERR_TIMER_EXPIRED) - TX_STAT_INC(qnum, timer_exp); + TX_STAT_INC(sc, qnum, timer_exp); if (ts->ts_flags & ATH9K_TX_DESC_CFG_ERR) - TX_STAT_INC(qnum, desc_cfg_err); + TX_STAT_INC(sc, qnum, desc_cfg_err); if (ts->ts_flags & ATH9K_TX_DATA_UNDERRUN) - TX_STAT_INC(qnum, data_underrun); + TX_STAT_INC(sc, qnum, data_underrun); if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN) - TX_STAT_INC(qnum, delim_underrun); -} - -static const struct file_operations fops_xmit = { - .read = read_file_xmit, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static const struct file_operations fops_queues = { - .read = read_file_queues, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static const struct file_operations fops_misc = { - .read = read_file_misc, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static const struct file_operations fops_reset = { - .read = read_file_reset, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_recv(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ -#define PHY_ERR(s, p) \ - len += snprintf(buf + len, size - len, "%22s : %10u\n", s, \ - sc->debug.stats.rxstats.phy_err_stats[p]); - -#define RXS_ERR(s, e) \ - do { \ - len += snprintf(buf + len, size - len, \ - "%22s : %10u\n", s, \ - sc->debug.stats.rxstats.e); \ - } while (0) - - struct ath_softc *sc = file->private_data; - char *buf; - unsigned int len = 0, size = 1600; - ssize_t retval = 0; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - RXS_ERR("CRC ERR", crc_err); - RXS_ERR("DECRYPT CRC ERR", decrypt_crc_err); - RXS_ERR("PHY ERR", phy_err); - RXS_ERR("MIC ERR", mic_err); - RXS_ERR("PRE-DELIM CRC ERR", pre_delim_crc_err); - RXS_ERR("POST-DELIM CRC ERR", post_delim_crc_err); - RXS_ERR("DECRYPT BUSY ERR", decrypt_busy_err); - RXS_ERR("RX-LENGTH-ERR", rx_len_err); - RXS_ERR("RX-OOM-ERR", rx_oom_err); - RXS_ERR("RX-RATE-ERR", rx_rate_err); - RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err); - - PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); - PHY_ERR("TIMING ERR", ATH9K_PHYERR_TIMING); - PHY_ERR("PARITY ERR", ATH9K_PHYERR_PARITY); - PHY_ERR("RATE ERR", ATH9K_PHYERR_RATE); - PHY_ERR("LENGTH ERR", ATH9K_PHYERR_LENGTH); - PHY_ERR("RADAR ERR", ATH9K_PHYERR_RADAR); - PHY_ERR("SERVICE ERR", ATH9K_PHYERR_SERVICE); - PHY_ERR("TOR ERR", ATH9K_PHYERR_TOR); - PHY_ERR("OFDM-TIMING ERR", ATH9K_PHYERR_OFDM_TIMING); - PHY_ERR("OFDM-SIGNAL-PARITY ERR", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); - PHY_ERR("OFDM-RATE ERR", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); - PHY_ERR("OFDM-LENGTH ERR", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); - PHY_ERR("OFDM-POWER-DROP ERR", ATH9K_PHYERR_OFDM_POWER_DROP); - PHY_ERR("OFDM-SERVICE ERR", ATH9K_PHYERR_OFDM_SERVICE); - PHY_ERR("OFDM-RESTART ERR", ATH9K_PHYERR_OFDM_RESTART); - PHY_ERR("FALSE-RADAR-EXT ERR", ATH9K_PHYERR_FALSE_RADAR_EXT); - PHY_ERR("CCK-TIMING ERR", ATH9K_PHYERR_CCK_TIMING); - PHY_ERR("CCK-HEADER-CRC ERR", ATH9K_PHYERR_CCK_HEADER_CRC); - PHY_ERR("CCK-RATE ERR", ATH9K_PHYERR_CCK_RATE_ILLEGAL); - PHY_ERR("CCK-SERVICE ERR", ATH9K_PHYERR_CCK_SERVICE); - PHY_ERR("CCK-RESTART ERR", ATH9K_PHYERR_CCK_RESTART); - PHY_ERR("CCK-LENGTH ERR", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); - PHY_ERR("CCK-POWER-DROP ERR", ATH9K_PHYERR_CCK_POWER_DROP); - PHY_ERR("HT-CRC ERR", ATH9K_PHYERR_HT_CRC_ERROR); - PHY_ERR("HT-LENGTH ERR", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); - PHY_ERR("HT-RATE ERR", ATH9K_PHYERR_HT_RATE_ILLEGAL); - - RXS_ERR("RX-Pkts-All", rx_pkts_all); - RXS_ERR("RX-Bytes-All", rx_bytes_all); - RXS_ERR("RX-Beacons", rx_beacons); - RXS_ERR("RX-Frags", rx_frags); - RXS_ERR("RX-Spectral", rx_spectral); - - if (len > size) - len = size; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; - -#undef RXS_ERR -#undef PHY_ERR + TX_STAT_INC(sc, qnum, delim_underrun); } void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) { -#define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ - - RX_STAT_INC(rx_pkts_all); - sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen; - - if (rs->rs_status & ATH9K_RXERR_CRC) - RX_STAT_INC(crc_err); - if (rs->rs_status & ATH9K_RXERR_DECRYPT) - RX_STAT_INC(decrypt_crc_err); - if (rs->rs_status & ATH9K_RXERR_MIC) - RX_STAT_INC(mic_err); - if (rs->rs_status & ATH9K_RX_DELIM_CRC_PRE) - RX_STAT_INC(pre_delim_crc_err); - if (rs->rs_status & ATH9K_RX_DELIM_CRC_POST) - RX_STAT_INC(post_delim_crc_err); - if (rs->rs_status & ATH9K_RX_DECRYPT_BUSY) - RX_STAT_INC(decrypt_busy_err); - - if (rs->rs_status & ATH9K_RXERR_PHY) { - RX_STAT_INC(phy_err); - if (rs->rs_phyerr < ATH9K_PHYERR_MAX) - RX_PHY_ERR_INC(rs->rs_phyerr); - } - -#undef RX_PHY_ERR_INC -} - -static const struct file_operations fops_recv = { - .read = read_file_recv, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char *mode = ""; - unsigned int len; - - switch (sc->spectral_mode) { - case SPECTRAL_DISABLED: - mode = "disable"; - break; - case SPECTRAL_BACKGROUND: - mode = "background"; - break; - case SPECTRAL_CHANSCAN: - mode = "chanscan"; - break; - case SPECTRAL_MANUAL: - mode = "manual"; - break; - } - len = strlen(mode); - return simple_read_from_buffer(user_buf, count, ppos, mode, len); -} - -static ssize_t write_file_spec_scan_ctl(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - - if (strncmp("trigger", buf, 7) == 0) { - ath9k_spectral_scan_trigger(sc->hw); - } else if (strncmp("background", buf, 9) == 0) { - ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND); - ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n"); - } else if (strncmp("chanscan", buf, 8) == 0) { - ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN); - ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n"); - } else if (strncmp("manual", buf, 6) == 0) { - ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL); - ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n"); - } else if (strncmp("disable", buf, 7) == 0) { - ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED); - ath_dbg(common, CONFIG, "spectral scan: disabled\n"); - } else { - return -EINVAL; - } - - return count; -} - -static const struct file_operations fops_spec_scan_ctl = { - .read = read_file_spec_scan_ctl, - .write = write_file_spec_scan_ctl, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_spectral_short_repeat(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[32]; - unsigned int len; - - len = sprintf(buf, "%d\n", sc->spec_config.short_repeat); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_spectral_short_repeat(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - unsigned long val; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, &val)) - return -EINVAL; - - if (val < 0 || val > 1) - return -EINVAL; - - sc->spec_config.short_repeat = val; - return count; -} - -static const struct file_operations fops_spectral_short_repeat = { - .read = read_file_spectral_short_repeat, - .write = write_file_spectral_short_repeat, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_spectral_count(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[32]; - unsigned int len; - - len = sprintf(buf, "%d\n", sc->spec_config.count); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); + ath9k_cmn_debug_stat_rx(&sc->debug.stats.rxstats, rs); } -static ssize_t write_file_spectral_count(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - unsigned long val; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, &val)) - return -EINVAL; - - if (val < 0 || val > 255) - return -EINVAL; - - sc->spec_config.count = val; - return count; -} - -static const struct file_operations fops_spectral_count = { - .read = read_file_spectral_count, - .write = write_file_spectral_count, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_spectral_period(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[32]; - unsigned int len; - - len = sprintf(buf, "%d\n", sc->spec_config.period); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_spectral_period(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - unsigned long val; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, &val)) - return -EINVAL; - - if (val < 0 || val > 255) - return -EINVAL; - - sc->spec_config.period = val; - return count; -} - -static const struct file_operations fops_spectral_period = { - .read = read_file_spectral_period, - .write = write_file_spectral_period, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_spectral_fft_period(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - char buf[32]; - unsigned int len; - - len = sprintf(buf, "%d\n", sc->spec_config.fft_period); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t write_file_spectral_fft_period(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_softc *sc = file->private_data; - unsigned long val; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, &val)) - return -EINVAL; - - if (val < 0 || val > 15) - return -EINVAL; - - sc->spec_config.fft_period = val; - return count; -} - -static const struct file_operations fops_spectral_fft_period = { - .read = read_file_spectral_fft_period, - .write = write_file_spectral_fft_period, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static struct dentry *create_buf_file_handler(const char *filename, - struct dentry *parent, - umode_t mode, - struct rchan_buf *buf, - int *is_global) -{ - struct dentry *buf_file; - - buf_file = debugfs_create_file(filename, mode, parent, buf, - &relay_file_operations); - *is_global = 1; - return buf_file; -} - -static int remove_buf_file_handler(struct dentry *dentry) -{ - debugfs_remove(dentry); - - return 0; -} - -void ath_debug_send_fft_sample(struct ath_softc *sc, - struct fft_sample_tlv *fft_sample_tlv) -{ - int length; - if (!sc->rfs_chan_spec_scan) - return; - - length = __be16_to_cpu(fft_sample_tlv->length) + - sizeof(*fft_sample_tlv); - relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, length); -} - -static struct rchan_callbacks rfs_spec_scan_cb = { - .create_buf_file = create_buf_file_handler, - .remove_buf_file = remove_buf_file_handler, -}; - - static ssize_t read_file_regidx(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; char buf[32]; @@ -1258,20 +863,15 @@ static ssize_t read_file_regidx(struct file *file, char __user *user_buf, } static ssize_t write_file_regidx(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; unsigned long regidx; - char buf[32]; - ssize_t len; + ssize_t ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, ®idx)) - return -EINVAL; + ret = kstrtoul_from_user(user_buf, count, 0, ®idx); + if (ret) + return ret; sc->debug.regidx = regidx; return count; @@ -1286,7 +886,7 @@ static const struct file_operations fops_regidx = { }; static ssize_t read_file_regval(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_hw *ah = sc->sc_ah; @@ -1302,21 +902,16 @@ static ssize_t read_file_regval(struct file *file, char __user *user_buf, } static ssize_t write_file_regval(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_hw *ah = sc->sc_ah; unsigned long regval; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; + ssize_t ret; - buf[len] = '\0'; - if (kstrtoul(buf, 0, ®val)) - return -EINVAL; + ret = kstrtoul_from_user(user_buf, count, 0, ®val); + if (ret) + return ret; ath9k_ps_wakeup(sc); REG_WRITE_D(ah, sc->debug.regidx, regval); @@ -1339,10 +934,21 @@ static int open_file_regdump(struct inode *inode, struct file *file) struct ath_softc *sc = inode->i_private; unsigned int len = 0; u8 *buf; - int i; + int i, j = 0; unsigned long num_regs, regdump_len, max_reg_offset; - - max_reg_offset = AR_SREV_9300_20_OR_LATER(sc->sc_ah) ? 0x16bd4 : 0xb500; + static const struct reg_hole { + u32 start; + u32 end; + } reg_hole_list[] = { + {0x0200, 0x07fc}, + {0x0c00, 0x0ffc}, + {0x2000, 0x3ffc}, + {0x4100, 0x6ffc}, + {0x705c, 0x7ffc}, + {0x0000, 0x0000} + }; + + max_reg_offset = AR_SREV_9300_20_OR_LATER(sc->sc_ah) ? 0x8800 : 0xb500; num_regs = max_reg_offset / 4 + 1; regdump_len = num_regs * REGDUMP_LINE_SIZE + 1; buf = vmalloc(regdump_len); @@ -1350,9 +956,16 @@ static int open_file_regdump(struct inode *inode, struct file *file) return -ENOMEM; ath9k_ps_wakeup(sc); - for (i = 0; i < num_regs; i++) + for (i = 0; i < num_regs; i++) { + if (reg_hole_list[j].start == i << 2) { + i = reg_hole_list[j].end >> 2; + j++; + continue; + } + len += scnprintf(buf + len, regdump_len - len, "0x%06x 0x%08x\n", i << 2, REG_READ(sc->sc_ah, i << 2)); + } ath9k_ps_restore(sc); file->private_data = buf; @@ -1368,240 +981,275 @@ static const struct file_operations fops_regdump = { .llseek = default_llseek,/* read accesses f_pos */ }; -static ssize_t read_file_dump_nfcal(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static int read_file_dump_nfcal(struct seq_file *file, void *data) { - struct ath_softc *sc = file->private_data; + struct ieee80211_hw *hw = dev_get_drvdata(file->private); + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; - struct ath9k_nfcal_hist *h = sc->caldata.nfCalHist; + struct ath9k_nfcal_hist *h = sc->cur_chan->caldata.nfCalHist; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &common->hw->conf; - u32 len = 0, size = 1500; u32 i, j; - ssize_t retval = 0; - char *buf; u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; u8 nread; - buf = kzalloc(size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - len += snprintf(buf + len, size - len, - "Channel Noise Floor : %d\n", ah->noise); - len += snprintf(buf + len, size - len, - "Chain | privNF | # Readings | NF Readings\n"); + seq_printf(file, "Channel Noise Floor : %d\n", ah->noise); + seq_puts(file, "Chain | privNF | # Readings | NF Readings\n"); for (i = 0; i < NUM_NF_READINGS; i++) { if (!(chainmask & (1 << i)) || ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))) continue; nread = AR_PHY_CCA_FILTERWINDOW_LENGTH - h[i].invalidNFcount; - len += snprintf(buf + len, size - len, " %d\t %d\t %d\t\t", - i, h[i].privNF, nread); + seq_printf(file, " %d\t %d\t %d\t\t", i, h[i].privNF, nread); for (j = 0; j < nread; j++) - len += snprintf(buf + len, size - len, - " %d", h[i].nfCalBuffer[j]); - len += snprintf(buf + len, size - len, "\n"); + seq_printf(file, " %d", h[i].nfCalBuffer[j]); + seq_puts(file, "\n"); } - if (len > size) - len = size; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; + return 0; } -static const struct file_operations fops_dump_nfcal = { - .read = read_file_dump_nfcal, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT +static ssize_t read_file_btcoex(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; - struct ath_hw *ah = sc->sc_ah; u32 len = 0, size = 1500; - ssize_t retval = 0; char *buf; + size_t retval; buf = kzalloc(size, GFP_KERNEL); - if (!buf) + if (buf == NULL) return -ENOMEM; - len = ah->eep_ops->dump_eeprom(ah, true, buf, len, size); + if (!sc->sc_ah->common.btcoex_enabled) { + len = scnprintf(buf, size, "%s\n", + "BTCOEX is disabled"); + goto exit; + } + len = ath9k_dump_btcoex(sc, buf, size); +exit: retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); kfree(buf); return retval; } -static const struct file_operations fops_base_eeprom = { - .read = read_file_base_eeprom, +static const struct file_operations fops_btcoex = { + .read = read_file_btcoex, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; +#endif -static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +#ifdef CONFIG_ATH9K_DYNACK +static ssize_t read_file_ackto(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_hw *ah = sc->sc_ah; - u32 len = 0, size = 6000; - char *buf; - size_t retval; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; + char buf[32]; + unsigned int len; - len = ah->eep_ops->dump_eeprom(ah, false, buf, len, size); + len = sprintf(buf, "%u %c\n", ah->dynack.ackto, + (ah->dynack.enabled) ? 'A' : 'S'); - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; + return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -static const struct file_operations fops_modal_eeprom = { - .read = read_file_modal_eeprom, +static const struct file_operations fops_ackto = { + .read = read_file_ackto, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; +#endif -#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT -static ssize_t read_file_btcoex(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +#ifdef CONFIG_ATH9K_WOW + +static ssize_t read_file_wow(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; - u32 len = 0, size = 1500; + unsigned int len = 0, size = 32; + ssize_t retval; char *buf; - size_t retval; buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) + if (!buf) return -ENOMEM; - if (!sc->sc_ah->common.btcoex_enabled) { - len = snprintf(buf, size, "%s\n", - "BTCOEX is disabled"); - goto exit; - } + len += scnprintf(buf + len, size - len, "WOW: %s\n", + sc->force_wow ? "ENABLED" : "DISABLED"); + + if (len > size) + len = size; - len = ath9k_dump_btcoex(sc, buf, size); -exit: retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); kfree(buf); return retval; } -static const struct file_operations fops_btcoex = { - .read = read_file_btcoex, +static ssize_t write_file_wow(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + unsigned long val; + ssize_t ret; + + ret = kstrtoul_from_user(user_buf, count, 0, &val); + if (ret) + return ret; + + if (val != 1) + return -EINVAL; + + if (!sc->force_wow) { + sc->force_wow = true; + ath9k_init_wow(sc->hw); + } + + return count; +} + +static const struct file_operations fops_wow = { + .read = read_file_wow, + .write = write_file_wow, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; + #endif -static ssize_t read_file_node_stat(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t read_file_tpc(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { - struct ath_node *an = file->private_data; - struct ath_softc *sc = an->sc; - struct ath_atx_tid *tid; - struct ath_atx_ac *ac; - struct ath_txq *txq; - u32 len = 0, size = 4096; + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + unsigned int len = 0, size = 32; + ssize_t retval; char *buf; - size_t retval; - int tidno, acno; buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) + if (!buf) return -ENOMEM; - if (!an->sta->ht_cap.ht_supported) { - len = snprintf(buf, size, "%s\n", - "HT not supported"); - goto exit; - } + len += scnprintf(buf + len, size - len, "%s\n", + ah->tpc_enabled ? "ENABLED" : "DISABLED"); - len = snprintf(buf, size, "Max-AMPDU: %d\n", - an->maxampdu); - len += snprintf(buf + len, size - len, "MPDU Density: %d\n\n", - an->mpdudensity); - - len += snprintf(buf + len, size - len, - "%2s%7s\n", "AC", "SCHED"); - - for (acno = 0, ac = &an->ac[acno]; - acno < IEEE80211_NUM_ACS; acno++, ac++) { - txq = ac->txq; - ath_txq_lock(sc, txq); - len += snprintf(buf + len, size - len, - "%2d%7d\n", - acno, ac->sched); - ath_txq_unlock(sc, txq); - } + if (len > size) + len = size; - len += snprintf(buf + len, size - len, - "\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n", - "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE", - "BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED"); - - for (tidno = 0, tid = &an->tid[tidno]; - tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { - txq = tid->ac->txq; - ath_txq_lock(sc, txq); - len += snprintf(buf + len, size - len, - "%3d%11d%10d%10d%10d%10d%9d%6d%8d\n", - tid->tidno, tid->seq_start, tid->seq_next, - tid->baw_size, tid->baw_head, tid->baw_tail, - tid->bar_index, tid->sched, tid->paused); - ath_txq_unlock(sc, txq); - } -exit: retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); kfree(buf); return retval; } -static const struct file_operations fops_node_stat = { - .read = read_file_node_stat, +static ssize_t write_file_tpc(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + unsigned long val; + ssize_t ret; + bool tpc_enabled; + + ret = kstrtoul_from_user(user_buf, count, 0, &val); + if (ret) + return ret; + + if (val > 1) + return -EINVAL; + + tpc_enabled = !!val; + + if (tpc_enabled != ah->tpc_enabled) { + ah->tpc_enabled = tpc_enabled; + + mutex_lock(&sc->mutex); + ath9k_set_txpower(sc, NULL); + mutex_unlock(&sc->mutex); + } + + return count; +} + +static const struct file_operations fops_tpc = { + .read = read_file_tpc, + .write = write_file_tpc, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; -void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct dentry *dir) +static ssize_t read_file_nf_override(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { - struct ath_node *an = (struct ath_node *)sta->drv_priv; - an->node_stat = debugfs_create_file("node_stat", S_IRUGO, - dir, an, &fops_node_stat); + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + char buf[32]; + unsigned int len; + + if (ah->nf_override == 0) + len = sprintf(buf, "off\n"); + else + len = sprintf(buf, "%d\n", ah->nf_override); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct dentry *dir) +static ssize_t write_file_nf_override(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) { - struct ath_node *an = (struct ath_node *)sta->drv_priv; - debugfs_remove(an->node_stat); + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + long val; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (strncmp("off", buf, 3) == 0) + val = 0; + else if (kstrtol(buf, 0, &val)) + return -EINVAL; + + if (val > 0) + return -EINVAL; + + if (val < -120) + return -EINVAL; + + ah->nf_override = val; + + if (ah->curchan) { + ath9k_ps_wakeup(sc); + ath9k_hw_loadnf(ah, ah->curchan); + ath9k_ps_restore(sc); + } + + return count; } +static const struct file_operations fops_nf_override = { + .read = read_file_nf_override, + .write = write_file_nf_override, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + /* Ethtool support for get-stats */ #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" @@ -1617,7 +1265,6 @@ static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = { AMKSTR(d_tx_mpdu_xretries), AMKSTR(d_tx_aggregates), AMKSTR(d_tx_ampdus_queued_hw), - AMKSTR(d_tx_ampdus_queued_sw), AMKSTR(d_tx_ampdus_completed), AMKSTR(d_tx_ampdu_retries), AMKSTR(d_tx_ampdu_xretries), @@ -1647,7 +1294,7 @@ void ath9k_get_et_strings(struct ieee80211_hw *hw, u32 sset, u8 *data) { if (sset == ETH_SS_STATS) - memcpy(data, *ath9k_gstrings_stats, + memcpy(data, ath9k_gstrings_stats, sizeof(ath9k_gstrings_stats)); } @@ -1679,11 +1326,11 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; int i = 0; - data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_pkts_all + + data[i++] = ((u64)sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_pkts_all + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_pkts_all + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_pkts_all + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_pkts_all); - data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_bytes_all + + data[i++] = ((u64)sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_bytes_all + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_bytes_all + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_bytes_all + sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_bytes_all); @@ -1697,7 +1344,6 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw, AWDATA(xretries); AWDATA(a_aggr); AWDATA(a_queued_hw); - AWDATA(a_queued_sw); AWDATA(a_completed); AWDATA(a_retries); AWDATA(a_xretries); @@ -1725,100 +1371,91 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw, void ath9k_deinit_debug(struct ath_softc *sc) { - if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) { - relay_close(sc->rfs_chan_spec_scan); - sc->rfs_chan_spec_scan = NULL; - } + ath9k_cmn_spectral_deinit_debug(&sc->spec_priv); } int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; sc->debug.debugfs_phy = debugfs_create_dir("ath9k", sc->hw->wiphy->debugfsdir); - if (!sc->debug.debugfs_phy) - return -ENOMEM; #ifdef CONFIG_ATH_DEBUG - debugfs_create_file("debug", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + debugfs_create_file("debug", 0600, sc->debug.debugfs_phy, sc, &fops_debug); #endif ath9k_dfs_init_debug(sc); - - debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_dma); - debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_interrupt); - debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_xmit); - debugfs_create_file("queues", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_queues); - debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, - &sc->tx.txq_max_pending[IEEE80211_AC_BK]); - debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, - &sc->tx.txq_max_pending[IEEE80211_AC_BE]); - debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, - &sc->tx.txq_max_pending[IEEE80211_AC_VI]); - debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, - &sc->tx.txq_max_pending[IEEE80211_AC_VO]); - debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_misc); - debugfs_create_file("reset", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_reset); - debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_recv); - debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_rx_chainmask); - debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_tx_chainmask); - debugfs_create_file("ani", S_IRUSR | S_IWUSR, + ath9k_tx99_init_debug(sc); + ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy); + + debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy, + read_file_dma); + debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy, + read_file_interrupt); + debugfs_create_devm_seqfile(sc->dev, "xmit", sc->debug.debugfs_phy, + read_file_xmit); + debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy, + read_file_queues); + debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy, + read_file_misc); + debugfs_create_file("reset", 0600, sc->debug.debugfs_phy, + sc, &fops_reset); + + ath9k_cmn_debug_recv(sc->debug.debugfs_phy, &sc->debug.stats.rxstats); + ath9k_cmn_debug_phy_err(sc->debug.debugfs_phy, &sc->debug.stats.rxstats); + + debugfs_create_u8("rx_chainmask", 0400, sc->debug.debugfs_phy, + &ah->rxchainmask); + debugfs_create_u8("tx_chainmask", 0400, sc->debug.debugfs_phy, + &ah->txchainmask); + debugfs_create_file("ani", 0600, sc->debug.debugfs_phy, sc, &fops_ani); - debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + debugfs_create_bool("paprd", 0600, sc->debug.debugfs_phy, &sc->sc_ah->config.enable_paprd); - debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + debugfs_create_file("regidx", 0600, sc->debug.debugfs_phy, sc, &fops_regidx); - debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + debugfs_create_file("regval", 0600, sc->debug.debugfs_phy, sc, &fops_regval); - debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR, + debugfs_create_bool("ignore_extcca", 0600, sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca); - debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc, + debugfs_create_file("regdump", 0400, sc->debug.debugfs_phy, sc, &fops_regdump); - debugfs_create_file("dump_nfcal", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_dump_nfcal); - debugfs_create_file("base_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_base_eeprom); - debugfs_create_file("modal_eeprom", S_IRUSR, sc->debug.debugfs_phy, sc, - &fops_modal_eeprom); - sc->rfs_chan_spec_scan = relay_open("spectral_scan", - sc->debug.debugfs_phy, - 1024, 256, &rfs_spec_scan_cb, - NULL); - debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, - &fops_spec_scan_ctl); - debugfs_create_file("spectral_short_repeat", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, - &fops_spectral_short_repeat); - debugfs_create_file("spectral_count", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_spectral_count); - debugfs_create_file("spectral_period", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_spectral_period); - debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, - &fops_spectral_fft_period); - debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, + debugfs_create_devm_seqfile(sc->dev, "dump_nfcal", + sc->debug.debugfs_phy, + read_file_dump_nfcal); + + ath9k_cmn_debug_base_eeprom(sc->debug.debugfs_phy, sc->sc_ah); + ath9k_cmn_debug_modal_eeprom(sc->debug.debugfs_phy, sc->sc_ah); + + debugfs_create_u32("gpio_mask", 0600, sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); - debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, + debugfs_create_u32("gpio_val", 0600, sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); - debugfs_create_file("diversity", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_ant_diversity); + debugfs_create_file("antenna_diversity", 0400, + sc->debug.debugfs_phy, sc, &fops_antenna_diversity); #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT - debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc, + debugfs_create_file("bt_ant_diversity", 0600, + sc->debug.debugfs_phy, sc, &fops_bt_ant_diversity); + debugfs_create_file("btcoex", 0400, sc->debug.debugfs_phy, sc, &fops_btcoex); #endif + +#ifdef CONFIG_ATH9K_WOW + debugfs_create_file("wow", 0600, sc->debug.debugfs_phy, sc, &fops_wow); +#endif + +#ifdef CONFIG_ATH9K_DYNACK + debugfs_create_file("ack_to", 0400, sc->debug.debugfs_phy, + sc, &fops_ackto); +#endif + debugfs_create_file("tpc", 0600, sc->debug.debugfs_phy, sc, &fops_tpc); + + debugfs_create_file("nf_override", 0600, + sc->debug.debugfs_phy, sc, &fops_nf_override); + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index fc679198a0f3..cb3e75969875 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -18,7 +18,6 @@ #define DEBUG_H #include "hw.h" -#include "rc.h" #include "dfs_debug.h" struct ath_txq; @@ -26,23 +25,35 @@ struct ath_buf; struct fft_sample_tlv; #ifdef CONFIG_ATH9K_DEBUGFS -#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++ -#define RESET_STAT_INC(sc, type) sc->debug.stats.reset[type]++ +#define TX_STAT_INC(sc, q, c) do { (sc)->debug.stats.txstats[q].c++; } while (0) +#define RX_STAT_INC(sc, c) do { (sc)->debug.stats.rxstats.c++; } while (0) +#define RESET_STAT_INC(sc, type) do { (sc)->debug.stats.reset[type]++; } while (0) +#define ANT_STAT_INC(sc, i, c) do { (sc)->debug.stats.ant_stats[i].c++; } while (0) +#define ANT_LNA_INC(sc, i, c) do { (sc)->debug.stats.ant_stats[i].lna_recv_cnt[c]++; } while (0) #else -#define TX_STAT_INC(q, c) do { } while (0) -#define RESET_STAT_INC(sc, type) do { } while (0) +#define TX_STAT_INC(sc, q, c) do { (void)(sc); } while (0) +#define RX_STAT_INC(sc, c) do { (void)(sc); } while (0) +#define RESET_STAT_INC(sc, type) do { (void)(sc); } while (0) +#define ANT_STAT_INC(sc, i, c) do { (void)(sc); } while (0) +#define ANT_LNA_INC(sc, i, c) do { (void)(sc); } while (0) #endif enum ath_reset_type { + RESET_TYPE_USER, RESET_TYPE_BB_HANG, RESET_TYPE_BB_WATCHDOG, RESET_TYPE_FATAL_INT, RESET_TYPE_TX_ERROR, + RESET_TYPE_TX_GTT, RESET_TYPE_TX_HANG, RESET_TYPE_PLL_HANG, RESET_TYPE_MAC_HANG, RESET_TYPE_BEACON_STUCK, RESET_TYPE_MCI, + RESET_TYPE_CALIBRATION, + RESET_TX_DMA_ERROR, + RESET_RX_DMA_ERROR, + RESET_TYPE_RX_INACTIVE, __RESET_TYPE_MAX }; @@ -138,7 +149,6 @@ struct ath_interrupt_stats { * @completed: Total MPDUs (non-aggr) completed * @a_aggr: Total no. of aggregates queued * @a_queued_hw: Total AMPDUs queued to hardware - * @a_queued_sw: Total AMPDUs queued to software queues * @a_completed: Total AMPDUs completed * @a_retries: No. of AMPDUs retried (SW) * @a_xretries: No. of AMPDUs dropped due to xretries @@ -165,7 +175,6 @@ struct ath_tx_stats { u32 xretries; u32 a_aggr; u32 a_queued_hw; - u32 a_queued_sw; u32 a_completed; u32 a_retries; u32 a_xretries; @@ -189,58 +198,44 @@ struct ath_tx_stats { #define TXSTATS sc->debug.stats.txstats #define PR(str, elem) \ do { \ - len += snprintf(buf + len, size - len, \ - "%s%13u%11u%10u%10u\n", str, \ - TXSTATS[PR_QNUM(IEEE80211_AC_BE)].elem, \ - TXSTATS[PR_QNUM(IEEE80211_AC_BK)].elem, \ - TXSTATS[PR_QNUM(IEEE80211_AC_VI)].elem, \ - TXSTATS[PR_QNUM(IEEE80211_AC_VO)].elem); \ + seq_printf(file, "%s%13u%11u%10u%10u\n", str, \ + TXSTATS[PR_QNUM(IEEE80211_AC_BE)].elem,\ + TXSTATS[PR_QNUM(IEEE80211_AC_BK)].elem,\ + TXSTATS[PR_QNUM(IEEE80211_AC_VI)].elem,\ + TXSTATS[PR_QNUM(IEEE80211_AC_VO)].elem); \ } while(0) -#define RX_STAT_INC(c) (sc->debug.stats.rxstats.c++) +struct ath_rx_rate_stats { + struct { + u32 ht20_cnt; + u32 ht40_cnt; + u32 sgi_cnt; + u32 lgi_cnt; + } ht_stats[24]; -/** - * struct ath_rx_stats - RX Statistics - * @rx_pkts_all: No. of total frames received, including ones that - may have had errors. - * @rx_bytes_all: No. of total bytes received, including ones that - may have had errors. - * @crc_err: No. of frames with incorrect CRC value - * @decrypt_crc_err: No. of frames whose CRC check failed after - decryption process completed - * @phy_err: No. of frames whose reception failed because the PHY - encountered an error - * @mic_err: No. of frames with incorrect TKIP MIC verification failure - * @pre_delim_crc_err: Pre-Frame delimiter CRC error detections - * @post_delim_crc_err: Post-Frame delimiter CRC error detections - * @decrypt_busy_err: Decryption interruptions counter - * @phy_err_stats: Individual PHY error statistics - * @rx_len_err: No. of frames discarded due to bad length. - * @rx_oom_err: No. of frames dropped due to OOM issues. - * @rx_rate_err: No. of frames dropped due to rate errors. - * @rx_too_many_frags_err: Frames dropped due to too-many-frags received. - * @rx_beacons: No. of beacons received. - * @rx_frags: No. of rx-fragements received. - * @rx_spectral: No of spectral packets received. - */ -struct ath_rx_stats { - u32 rx_pkts_all; - u32 rx_bytes_all; - u32 crc_err; - u32 decrypt_crc_err; - u32 phy_err; - u32 mic_err; - u32 pre_delim_crc_err; - u32 post_delim_crc_err; - u32 decrypt_busy_err; - u32 phy_err_stats[ATH9K_PHYERR_MAX]; - u32 rx_len_err; - u32 rx_oom_err; - u32 rx_rate_err; - u32 rx_too_many_frags_err; - u32 rx_beacons; - u32 rx_frags; - u32 rx_spectral; + struct { + u32 ofdm_cnt; + } ofdm_stats[8]; + + struct { + u32 cck_lp_cnt; + u32 cck_sp_cnt; + } cck_stats[4]; +}; + +struct ath_airtime_stats { + u32 rx_airtime; + u32 tx_airtime; +}; + +#define ANT_MAIN 0 +#define ANT_ALT 1 + +struct ath_antenna_stats { + u32 recv_cnt; + u32 rssi_avg; + u32 lna_recv_cnt[4]; + u32 lna_attempt_cnt[4]; }; struct ath_stats { @@ -248,6 +243,7 @@ struct ath_stats { struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; struct ath_rx_stats rxstats; struct ath_dfs_stats dfs_stats; + struct ath_antenna_stats ant_stats[2]; u32 reset[__RESET_TYPE_MAX]; }; @@ -277,18 +273,13 @@ void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); -void ath9k_sta_remove_debugfs(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct dentry *dir); - -void ath_debug_send_fft_sample(struct ath_softc *sc, - struct fft_sample_tlv *fft_sample); +void ath9k_debug_stat_ant(struct ath_softc *sc, + struct ath_hw_antcomb_conf *div_ant_conf, + int main_rssi_avg, int alt_rssi_avg); +void ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause); #else -#define RX_STAT_INC(c) /* NOP */ - static inline int ath9k_init_debug(struct ath_hw *ah) { return 0; @@ -297,12 +288,10 @@ static inline int ath9k_init_debug(struct ath_hw *ah) static inline void ath9k_deinit_debug(struct ath_softc *sc) { } - static inline void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) { } - static inline void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, @@ -310,12 +299,34 @@ static inline void ath_debug_stat_tx(struct ath_softc *sc, unsigned int flags) { } - static inline void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) { } +static inline void ath9k_debug_stat_ant(struct ath_softc *sc, + struct ath_hw_antcomb_conf *div_ant_conf, + int main_rssi_avg, int alt_rssi_avg) +{ + +} + +static inline void +ath9k_debug_sync_cause(struct ath_softc *sc, u32 sync_cause) +{ +} #endif /* CONFIG_ATH9K_DEBUGFS */ +#ifdef CONFIG_ATH9K_STATION_STATISTICS +void ath_debug_rate_stats(struct ath_softc *sc, + struct ath_rx_status *rs, + struct sk_buff *skb); +#else +static inline void ath_debug_rate_stats(struct ath_softc *sc, + struct ath_rx_status *rs, + struct sk_buff *skb) +{ +} +#endif /* CONFIG_ATH9K_STATION_STATISTICS */ + #endif /* DEBUG_H */ diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c new file mode 100644 index 000000000000..1e2a30019fb6 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/debug_sta.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2013 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +/*************/ +/* node_aggr */ +/*************/ + +static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_node *an = file->private_data; + struct ath_softc *sc = an->sc; + struct ath_atx_tid *tid; + struct ath_txq *txq; + u32 len = 0, size = 4096; + char *buf; + size_t retval; + int tidno; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + if (!an->sta->deflink.ht_cap.ht_supported) { + len = scnprintf(buf, size, "%s\n", + "HT not supported"); + goto exit; + } + + len = scnprintf(buf, size, "Max-AMPDU: %d\n", + an->maxampdu); + len += scnprintf(buf + len, size - len, "MPDU Density: %d\n\n", + an->mpdudensity); + + len += scnprintf(buf + len, size - len, + "\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n", + "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE", + "BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED"); + + for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { + tid = ath_node_to_tid(an, tidno); + txq = tid->txq; + ath_txq_lock(sc, txq); + if (tid->active) { + len += scnprintf(buf + len, size - len, + "%3d%11d%10d%10d%10d%10d%9d%6d\n", + tid->tidno, + tid->seq_start, + tid->seq_next, + tid->baw_size, + tid->baw_head, + tid->baw_tail, + tid->bar_index, + !list_empty(&tid->list)); + } + ath_txq_unlock(sc, txq); + } +exit: + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_node_aggr = { + .read = read_file_node_aggr, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +/*************/ +/* node_recv */ +/*************/ + +void ath_debug_rate_stats(struct ath_softc *sc, + struct ath_rx_status *rs, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ath_hw *ah = sc->sc_ah; + struct ieee80211_rx_status *rxs; + struct ath_rx_rate_stats *rstats; + struct ieee80211_sta *sta; + struct ath_node *an; + + if (!ieee80211_is_data(hdr->frame_control)) + return; + + rcu_read_lock(); + + sta = ieee80211_find_sta_by_ifaddr(sc->hw, hdr->addr2, NULL); + if (!sta) + goto exit; + + an = (struct ath_node *) sta->drv_priv; + rstats = &an->rx_rate_stats; + rxs = IEEE80211_SKB_RXCB(skb); + + if (IS_HT_RATE(rs->rs_rate)) { + if (rxs->rate_idx >= ARRAY_SIZE(rstats->ht_stats)) + goto exit; + + if (rxs->bw == RATE_INFO_BW_40) + rstats->ht_stats[rxs->rate_idx].ht40_cnt++; + else + rstats->ht_stats[rxs->rate_idx].ht20_cnt++; + + if (rxs->enc_flags & RX_ENC_FLAG_SHORT_GI) + rstats->ht_stats[rxs->rate_idx].sgi_cnt++; + else + rstats->ht_stats[rxs->rate_idx].lgi_cnt++; + + goto exit; + } + + if (IS_CCK_RATE(rs->rs_rate)) { + if (rxs->enc_flags & RX_ENC_FLAG_SHORTPRE) + rstats->cck_stats[rxs->rate_idx].cck_sp_cnt++; + else + rstats->cck_stats[rxs->rate_idx].cck_lp_cnt++; + + goto exit; + } + + if (IS_OFDM_RATE(rs->rs_rate)) { + if (ah->curchan->chan->band == NL80211_BAND_2GHZ) + rstats->ofdm_stats[rxs->rate_idx - 4].ofdm_cnt++; + else + rstats->ofdm_stats[rxs->rate_idx].ofdm_cnt++; + } +exit: + rcu_read_unlock(); +} + +#define PRINT_CCK_RATE(str, i, sp) \ + do { \ + len += scnprintf(buf + len, size - len, \ + "%11s : %10u\n", \ + str, \ + (sp) ? rstats->cck_stats[i].cck_sp_cnt : \ + rstats->cck_stats[i].cck_lp_cnt); \ + } while (0) + +#define PRINT_OFDM_RATE(str, i) \ + do { \ + len += scnprintf(buf + len, size - len, \ + "%11s : %10u\n", \ + str, \ + rstats->ofdm_stats[i].ofdm_cnt); \ + } while (0) + +static ssize_t read_file_node_recv(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_node *an = file->private_data; + struct ath_softc *sc = an->sc; + struct ath_hw *ah = sc->sc_ah; + struct ath_rx_rate_stats *rstats; + struct ieee80211_sta *sta = an->sta; + enum nl80211_band band; + u32 len = 0, size = 4096; + char *buf; + size_t retval; + int i; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + band = ah->curchan->chan->band; + rstats = &an->rx_rate_stats; + + if (!sta->deflink.ht_cap.ht_supported) + goto legacy; + + len += scnprintf(buf + len, size - len, + "%24s%10s%10s%10s\n", + "HT20", "HT40", "SGI", "LGI"); + + for (i = 0; i < 24; i++) { + len += scnprintf(buf + len, size - len, + "%8s%3u : %10u%10u%10u%10u\n", + "MCS", i, + rstats->ht_stats[i].ht20_cnt, + rstats->ht_stats[i].ht40_cnt, + rstats->ht_stats[i].sgi_cnt, + rstats->ht_stats[i].lgi_cnt); + } + + len += scnprintf(buf + len, size - len, "\n"); + +legacy: + if (band == NL80211_BAND_2GHZ) { + PRINT_CCK_RATE("CCK-1M/LP", 0, false); + PRINT_CCK_RATE("CCK-2M/LP", 1, false); + PRINT_CCK_RATE("CCK-5.5M/LP", 2, false); + PRINT_CCK_RATE("CCK-11M/LP", 3, false); + + PRINT_CCK_RATE("CCK-2M/SP", 1, true); + PRINT_CCK_RATE("CCK-5.5M/SP", 2, true); + PRINT_CCK_RATE("CCK-11M/SP", 3, true); + } + + PRINT_OFDM_RATE("OFDM-6M", 0); + PRINT_OFDM_RATE("OFDM-9M", 1); + PRINT_OFDM_RATE("OFDM-12M", 2); + PRINT_OFDM_RATE("OFDM-18M", 3); + PRINT_OFDM_RATE("OFDM-24M", 4); + PRINT_OFDM_RATE("OFDM-36M", 5); + PRINT_OFDM_RATE("OFDM-48M", 6); + PRINT_OFDM_RATE("OFDM-54M", 7); + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +#undef PRINT_OFDM_RATE +#undef PRINT_CCK_RATE + +static const struct file_operations fops_node_recv = { + .read = read_file_node_recv, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct dentry *dir) +{ + struct ath_node *an = (struct ath_node *)sta->drv_priv; + + debugfs_create_file("node_aggr", 0444, dir, an, &fops_node_aggr); + debugfs_create_file("node_recv", 0444, dir, an, &fops_node_recv); +} diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c index 7187d3671512..2fb73a5e1d51 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.c +++ b/drivers/net/wireless/ath/ath9k/dfs.c @@ -30,6 +30,155 @@ struct ath_radar_data { u8 pulse_length_pri; }; +/**** begin: CHIRP ************************************************************/ + +/* min and max gradients for defined FCC chirping pulses, given by + * - 20MHz chirp width over a pulse width of 50us + * - 5MHz chirp width over a pulse width of 100us + */ +static const int BIN_DELTA_MIN = 1; +static const int BIN_DELTA_MAX = 10; + +/* we need at least 3 deltas / 4 samples for a reliable chirp detection */ +#define NUM_DIFFS 3 +#define FFT_NUM_SAMPLES (NUM_DIFFS + 1) + +/* Threshold for difference of delta peaks */ +static const int MAX_DIFF = 2; + +/* width range to be checked for chirping */ +static const int MIN_CHIRP_PULSE_WIDTH = 20; +static const int MAX_CHIRP_PULSE_WIDTH = 110; + +struct ath9k_dfs_fft_20 { + u8 bin[28]; + u8 lower_bins[3]; +} __packed; +struct ath9k_dfs_fft_40 { + u8 bin[64]; + u8 lower_bins[3]; + u8 upper_bins[3]; +} __packed; + +static inline int fft_max_index(u8 *bins) +{ + return (bins[2] & 0xfc) >> 2; +} +static inline int fft_max_magnitude(u8 *bins) +{ + return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10; +} +static inline u8 fft_bitmap_weight(u8 *bins) +{ + return bins[0] & 0x3f; +} + +static int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft, + bool is_ctl, bool is_ext) +{ + const int DFS_UPPER_BIN_OFFSET = 64; + /* if detected radar on both channels, select the significant one */ + if (is_ctl && is_ext) { + /* first check whether channels have 'strong' bins */ + is_ctl = fft_bitmap_weight(fft->lower_bins) != 0; + is_ext = fft_bitmap_weight(fft->upper_bins) != 0; + + /* if still unclear, take higher magnitude */ + if (is_ctl && is_ext) { + int mag_lower = fft_max_magnitude(fft->lower_bins); + int mag_upper = fft_max_magnitude(fft->upper_bins); + if (mag_upper > mag_lower) + is_ctl = false; + else + is_ext = false; + } + } + if (is_ctl) + return fft_max_index(fft->lower_bins); + return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET; +} +static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data, + int datalen, bool is_ctl, bool is_ext) +{ + int i; + int max_bin[FFT_NUM_SAMPLES]; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + int prev_delta; + + if (IS_CHAN_HT40(ah->curchan)) { + struct ath9k_dfs_fft_40 *fft = (struct ath9k_dfs_fft_40 *) data; + int num_fft_packets = datalen / sizeof(*fft); + if (num_fft_packets == 0) + return false; + + ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n", + datalen, num_fft_packets); + if (num_fft_packets < FFT_NUM_SAMPLES) { + ath_dbg(common, DFS, "not enough packets for chirp\n"); + return false; + } + /* HW sometimes adds 2 garbage bytes in front of FFT samples */ + if ((datalen % sizeof(*fft)) == 2) { + fft = (struct ath9k_dfs_fft_40 *) (data + 2); + ath_dbg(common, DFS, "fixing datalen by 2\n"); + } + if (IS_CHAN_HT40MINUS(ah->curchan)) + swap(is_ctl, is_ext); + + for (i = 0; i < FFT_NUM_SAMPLES; i++) + max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl, + is_ext); + } else { + struct ath9k_dfs_fft_20 *fft = (struct ath9k_dfs_fft_20 *) data; + int num_fft_packets = datalen / sizeof(*fft); + if (num_fft_packets == 0) + return false; + ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n", + datalen, num_fft_packets); + if (num_fft_packets < FFT_NUM_SAMPLES) { + ath_dbg(common, DFS, "not enough packets for chirp\n"); + return false; + } + /* in ht20, this is a 6-bit signed number => shift it to 0 */ + for (i = 0; i < FFT_NUM_SAMPLES; i++) + max_bin[i] = fft_max_index(fft[i].lower_bins) ^ 0x20; + } + ath_dbg(common, DFS, "bin_max = [%d, %d, %d, %d]\n", + max_bin[0], max_bin[1], max_bin[2], max_bin[3]); + + /* Check for chirp attributes within specs + * a) delta of adjacent max_bins is within range + * b) delta of adjacent deltas are within tolerance + */ + prev_delta = 0; + for (i = 0; i < NUM_DIFFS; i++) { + int ddelta = -1; + int delta = max_bin[i + 1] - max_bin[i]; + + /* ensure gradient is within valid range */ + if (abs(delta) < BIN_DELTA_MIN || abs(delta) > BIN_DELTA_MAX) { + ath_dbg(common, DFS, "CHIRP: invalid delta %d " + "in sample %d\n", delta, i); + return false; + } + if (i == 0) + goto done; + ddelta = delta - prev_delta; + if (abs(ddelta) > MAX_DIFF) { + ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n", + ddelta); + return false; + } +done: + ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n", + i, delta, ddelta); + prev_delta = delta; + } + return true; +} +/**** end: CHIRP **************************************************************/ + /* convert pulse duration to usecs, considering clock mode */ static u32 dur_to_usecs(struct ath_hw *ah, u32 dur) { @@ -97,7 +246,7 @@ ath9k_postprocess_radar_event(struct ath_softc *sc, DFS_STAT_INC(sc, dc_phy_errors); /* when both are present use stronger one */ - rssi = (ard->rssi < ard->ext_rssi) ? ard->ext_rssi : ard->rssi; + rssi = max(ard->rssi, ard->ext_rssi); break; default: /* @@ -113,12 +262,6 @@ ath9k_postprocess_radar_event(struct ath_softc *sc, return false; } - /* - * TODO: check chirping pulses - * checks for chirping are dependent on the DFS regulatory domain - * used, which is yet TBD - */ - /* convert duration to usecs */ pe->width = dur_to_usecs(sc->sc_ah, dur); pe->rssi = rssi; @@ -126,8 +269,19 @@ ath9k_postprocess_radar_event(struct ath_softc *sc, DFS_STAT_INC(sc, pulses_detected); return true; } -#undef PRI_CH_RADAR_FOUND -#undef EXT_CH_RADAR_FOUND + +static void +ath9k_dfs_process_radar_pulse(struct ath_softc *sc, struct pulse_event *pe) +{ + struct dfs_pattern_detector *pd = sc->dfs_detector; + DFS_STAT_INC(sc, pulses_processed); + if (pd == NULL) + return; + if (!pd->add_pulse(pd, pe, NULL)) + return; + DFS_STAT_INC(sc, radar_detected); + ieee80211_radar_detected(sc->hw, NULL); +} /* * DFS: check PHY-error for radar pulse and feed the detector @@ -158,8 +312,8 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, return; } - ard.rssi = rs->rs_rssi_ctl0; - ard.ext_rssi = rs->rs_rssi_ext0; + ard.rssi = rs->rs_rssi_ctl[0]; + ard.ext_rssi = rs->rs_rssi_ext[0]; /* * hardware stores this as 8 bit signed value. @@ -170,24 +324,38 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, if (ard.ext_rssi & 0x80) ard.ext_rssi = 0; - vdata_end = (char *)data + datalen; + vdata_end = data + datalen; ard.pulse_bw_info = vdata_end[-1]; ard.pulse_length_ext = vdata_end[-2]; ard.pulse_length_pri = vdata_end[-3]; pe.freq = ah->curchan->channel; pe.ts = mactime; - if (ath9k_postprocess_radar_event(sc, &ard, &pe)) { - struct dfs_pattern_detector *pd = sc->dfs_detector; - static u64 last_ts; - ath_dbg(common, DFS, - "ath9k_dfs_process_phyerr: channel=%d, ts=%llu, " - "width=%d, rssi=%d, delta_ts=%llu\n", - pe.freq, pe.ts, pe.width, pe.rssi, pe.ts-last_ts); - last_ts = pe.ts; - DFS_STAT_INC(sc, pulses_processed); - if (pd != NULL && pd->add_pulse(pd, &pe)) { - DFS_STAT_INC(sc, radar_detected); - ieee80211_radar_detected(sc->hw); - } + if (!ath9k_postprocess_radar_event(sc, &ard, &pe)) + return; + + if (pe.width > MIN_CHIRP_PULSE_WIDTH && + pe.width < MAX_CHIRP_PULSE_WIDTH) { + bool is_ctl = !!(ard.pulse_bw_info & PRI_CH_RADAR_FOUND); + bool is_ext = !!(ard.pulse_bw_info & EXT_CH_RADAR_FOUND); + int clen = datalen - 3; + pe.chirp = ath9k_check_chirping(sc, data, clen, is_ctl, is_ext); + } else { + pe.chirp = false; + } + + ath_dbg(common, DFS, + "ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, " + "width=%d, rssi=%d, delta_ts=%llu\n", + ard.pulse_bw_info, pe.freq, pe.ts, pe.width, pe.rssi, + pe.ts - sc->dfs_prev_pulse_ts); + sc->dfs_prev_pulse_ts = pe.ts; + if (ard.pulse_bw_info & PRI_CH_RADAR_FOUND) + ath9k_dfs_process_radar_pulse(sc, &pe); + if (IS_CHAN_HT40(ah->curchan) && + ard.pulse_bw_info & EXT_CH_RADAR_FOUND) { + pe.freq += IS_CHAN_HT40PLUS(ah->curchan) ? 20 : -20; + ath9k_dfs_process_radar_pulse(sc, &pe); } } +#undef PRI_CH_RADAR_FOUND +#undef EXT_CH_RADAR_FOUND diff --git a/drivers/net/wireless/ath/ath9k/dfs.h b/drivers/net/wireless/ath/ath9k/dfs.h index 3c839f06a06a..c6fa3d5b5d74 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.h +++ b/drivers/net/wireless/ath/ath9k/dfs.h @@ -17,7 +17,7 @@ #ifndef ATH9K_DFS_H #define ATH9K_DFS_H -#include "dfs_pattern_detector.h" +#include "../dfs_pattern_detector.h" #if defined(CONFIG_ATH9K_DFS_CERTIFIED) /** diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c index 3c6e4138a95d..426caa057396 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_debug.c +++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c @@ -20,16 +20,16 @@ #include "ath9k.h" #include "dfs_debug.h" +#include "../dfs_pattern_detector.h" - -struct ath_dfs_pool_stats global_dfs_pool_stats = { 0 }; +static struct ath_dfs_pool_stats dfs_pool_stats = { 0 }; #define ATH9K_DFS_STAT(s, p) \ - len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \ - sc->debug.stats.dfs_stats.p); + len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \ + sc->debug.stats.dfs_stats.p) #define ATH9K_DFS_POOL_STAT(s, p) \ - len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \ - global_dfs_pool_stats.p); + len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \ + dfs_pool_stats.p); static ssize_t read_file_dfs(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -44,12 +44,21 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf, if (buf == NULL) return -ENOMEM; - len += snprintf(buf + len, size - len, "DFS support for " - "macVersion = 0x%x, macRev = 0x%x: %s\n", - hw_ver->macVersion, hw_ver->macRev, - (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ? + len += scnprintf(buf + len, size - len, "DFS support for " + "macVersion = 0x%x, macRev = 0x%x: %s\n", + hw_ver->macVersion, hw_ver->macRev, + (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ? "enabled" : "disabled"); - len += snprintf(buf + len, size - len, "Pulse detector statistics:\n"); + + if (!sc->dfs_detector) { + len += scnprintf(buf + len, size - len, + "DFS detector not enabled\n"); + goto exit; + } + + dfs_pool_stats = sc->dfs_detector->get_stats(sc->dfs_detector); + + len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n"); ATH9K_DFS_STAT("pulse events reported ", pulses_total); ATH9K_DFS_STAT("invalid pulse events ", pulses_no_dfs); ATH9K_DFS_STAT("DFS pulses detected ", pulses_detected); @@ -59,11 +68,12 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf, ATH9K_DFS_STAT("Primary channel pulses ", pri_phy_errors); ATH9K_DFS_STAT("Secondary channel pulses", ext_phy_errors); ATH9K_DFS_STAT("Dual channel pulses ", dc_phy_errors); - len += snprintf(buf + len, size - len, "Radar detector statistics " - "(current DFS region: %d)\n", sc->dfs_detector->region); + len += scnprintf(buf + len, size - len, "Radar detector statistics " + "(current DFS region: %d)\n", + sc->dfs_detector->region); ATH9K_DFS_STAT("Pulse events processed ", pulses_processed); ATH9K_DFS_STAT("Radars detected ", radar_detected); - len += snprintf(buf + len, size - len, "Global Pool statistics:\n"); + len += scnprintf(buf + len, size - len, "Global Pool statistics:\n"); ATH9K_DFS_POOL_STAT("Pool references ", pool_reference); ATH9K_DFS_POOL_STAT("Pulses allocated ", pulse_allocated); ATH9K_DFS_POOL_STAT("Pulses alloc error ", pulse_alloc_error); @@ -72,6 +82,7 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf, ATH9K_DFS_POOL_STAT("Seqs. alloc error ", pseq_alloc_error); ATH9K_DFS_POOL_STAT("Seqs. in use ", pseq_used); +exit: if (len > size) len = size; @@ -88,17 +99,11 @@ static ssize_t write_file_dfs(struct file *file, const char __user *user_buf, { struct ath_softc *sc = file->private_data; unsigned long val; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - - buf[len] = '\0'; - if (kstrtoul(buf, 0, &val)) - return -EINVAL; + ssize_t ret; + ret = kstrtoul_from_user(user_buf, count, 0, &val); + if (ret) + return ret; if (val == DFS_STATS_RESET_MAGIC) memset(&sc->debug.stats.dfs_stats, 0, sizeof(sc->debug.stats.dfs_stats)); @@ -111,7 +116,7 @@ static ssize_t write_file_simulate_radar(struct file *file, { struct ath_softc *sc = file->private_data; - ieee80211_radar_detected(sc->hw); + ieee80211_radar_detected(sc->hw, NULL); return count; } @@ -133,8 +138,8 @@ static const struct file_operations fops_dfs_stats = { void ath9k_dfs_init_debug(struct ath_softc *sc) { - debugfs_create_file("dfs_stats", S_IRUSR, + debugfs_create_file("dfs_stats", 0400, sc->debug.debugfs_phy, sc, &fops_dfs_stats); - debugfs_create_file("dfs_simulate_radar", S_IWUSR, + debugfs_create_file("dfs_simulate_radar", 0200, sc->debug.debugfs_phy, sc, &fops_simulate_radar); } diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.h b/drivers/net/wireless/ath/ath9k/dfs_debug.h index e36810a4b585..7936c9126a20 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_debug.h +++ b/drivers/net/wireless/ath/ath9k/dfs_debug.h @@ -21,6 +21,8 @@ #include "hw.h" +struct ath_softc; + /** * struct ath_dfs_stats - DFS Statistics per wiphy * @pulses_total: pulses reported by HW @@ -51,25 +53,11 @@ struct ath_dfs_stats { u32 radar_detected; }; -/** - * struct ath_dfs_pool_stats - DFS Statistics for global pools - */ -struct ath_dfs_pool_stats { - u32 pool_reference; - u32 pulse_allocated; - u32 pulse_alloc_error; - u32 pulse_used; - u32 pseq_allocated; - u32 pseq_alloc_error; - u32 pseq_used; -}; #if defined(CONFIG_ATH9K_DFS_DEBUGFS) #define DFS_STAT_INC(sc, c) (sc->debug.stats.dfs_stats.c++) void ath9k_dfs_init_debug(struct ath_softc *sc); -#define DFS_POOL_STAT_INC(c) (global_dfs_pool_stats.c++) -#define DFS_POOL_STAT_DEC(c) (global_dfs_pool_stats.c--) extern struct ath_dfs_pool_stats global_dfs_pool_stats; #else @@ -77,8 +65,6 @@ extern struct ath_dfs_pool_stats global_dfs_pool_stats; #define DFS_STAT_INC(sc, c) do { } while (0) static inline void ath9k_dfs_init_debug(struct ath_softc *sc) { } -#define DFS_POOL_STAT_INC(c) do { } while (0) -#define DFS_POOL_STAT_DEC(c) do { } while (0) #endif /* CONFIG_ATH9K_DFS_DEBUGFS */ #endif /* ATH9K_DFS_DEBUG_H */ diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c deleted file mode 100644 index 491305c81fce..000000000000 --- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (c) 2012 Neratec Solutions AG - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/slab.h> -#include <linux/export.h> - -#include "dfs_pattern_detector.h" -#include "dfs_pri_detector.h" -#include "ath9k.h" - -/* - * tolerated deviation of radar time stamp in usecs on both sides - * TODO: this might need to be HW-dependent - */ -#define PRI_TOLERANCE 16 - -/** - * struct radar_types - contains array of patterns defined for one DFS domain - * @domain: DFS regulatory domain - * @num_radar_types: number of radar types to follow - * @radar_types: radar types array - */ -struct radar_types { - enum nl80211_dfs_regions region; - u32 num_radar_types; - const struct radar_detector_specs *radar_types; -}; - -/* percentage on ppb threshold to trigger detection */ -#define MIN_PPB_THRESH 50 -#define PPB_THRESH(PPB) ((PPB * MIN_PPB_THRESH + 50) / 100) -#define PRF2PRI(PRF) ((1000000 + PRF / 2) / PRF) -/* percentage of pulse width tolerance */ -#define WIDTH_TOLERANCE 5 -#define WIDTH_LOWER(X) ((X*(100-WIDTH_TOLERANCE)+50)/100) -#define WIDTH_UPPER(X) ((X*(100+WIDTH_TOLERANCE)+50)/100) - -#define ETSI_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB) \ -{ \ - ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \ - (PRF2PRI(PMAX) - PRI_TOLERANCE), \ - (PRF2PRI(PMIN) * PRF + PRI_TOLERANCE), PRF, PPB * PRF, \ - PPB_THRESH(PPB), PRI_TOLERANCE, \ -} - -/* radar types as defined by ETSI EN-301-893 v1.5.1 */ -static const struct radar_detector_specs etsi_radar_ref_types_v15[] = { - ETSI_PATTERN(0, 0, 1, 700, 700, 1, 18), - ETSI_PATTERN(1, 0, 5, 200, 1000, 1, 10), - ETSI_PATTERN(2, 0, 15, 200, 1600, 1, 15), - ETSI_PATTERN(3, 0, 15, 2300, 4000, 1, 25), - ETSI_PATTERN(4, 20, 30, 2000, 4000, 1, 20), - ETSI_PATTERN(5, 0, 2, 300, 400, 3, 10), - ETSI_PATTERN(6, 0, 2, 400, 1200, 3, 15), -}; - -static const struct radar_types etsi_radar_types_v15 = { - .region = NL80211_DFS_ETSI, - .num_radar_types = ARRAY_SIZE(etsi_radar_ref_types_v15), - .radar_types = etsi_radar_ref_types_v15, -}; - -/* for now, we support ETSI radar types, FCC and JP are TODO */ -static const struct radar_types *dfs_domains[] = { - &etsi_radar_types_v15, -}; - -/** - * get_dfs_domain_radar_types() - get radar types for a given DFS domain - * @param domain DFS domain - * @return radar_types ptr on success, NULL if DFS domain is not supported - */ -static const struct radar_types * -get_dfs_domain_radar_types(enum nl80211_dfs_regions region) -{ - u32 i; - for (i = 0; i < ARRAY_SIZE(dfs_domains); i++) { - if (dfs_domains[i]->region == region) - return dfs_domains[i]; - } - return NULL; -} - -/** - * struct channel_detector - detector elements for a DFS channel - * @head: list_head - * @freq: frequency for this channel detector in MHz - * @detectors: array of dynamically created detector elements for this freq - * - * Channel detectors are required to provide multi-channel DFS detection, e.g. - * to support off-channel scanning. A pattern detector has a list of channels - * radar pulses have been reported for in the past. - */ -struct channel_detector { - struct list_head head; - u16 freq; - struct pri_detector **detectors; -}; - -/* channel_detector_reset() - reset detector lines for a given channel */ -static void channel_detector_reset(struct dfs_pattern_detector *dpd, - struct channel_detector *cd) -{ - u32 i; - if (cd == NULL) - return; - for (i = 0; i < dpd->num_radar_types; i++) - cd->detectors[i]->reset(cd->detectors[i], dpd->last_pulse_ts); -} - -/* channel_detector_exit() - destructor */ -static void channel_detector_exit(struct dfs_pattern_detector *dpd, - struct channel_detector *cd) -{ - u32 i; - if (cd == NULL) - return; - list_del(&cd->head); - for (i = 0; i < dpd->num_radar_types; i++) { - struct pri_detector *de = cd->detectors[i]; - if (de != NULL) - de->exit(de); - } - kfree(cd->detectors); - kfree(cd); -} - -static struct channel_detector * -channel_detector_create(struct dfs_pattern_detector *dpd, u16 freq) -{ - u32 sz, i; - struct channel_detector *cd; - struct ath_common *common = ath9k_hw_common(dpd->ah); - - cd = kmalloc(sizeof(*cd), GFP_ATOMIC); - if (cd == NULL) - goto fail; - - INIT_LIST_HEAD(&cd->head); - cd->freq = freq; - sz = sizeof(cd->detectors) * dpd->num_radar_types; - cd->detectors = kzalloc(sz, GFP_ATOMIC); - if (cd->detectors == NULL) - goto fail; - - for (i = 0; i < dpd->num_radar_types; i++) { - const struct radar_detector_specs *rs = &dpd->radar_spec[i]; - struct pri_detector *de = pri_detector_init(rs); - if (de == NULL) - goto fail; - cd->detectors[i] = de; - } - list_add(&cd->head, &dpd->channel_detectors); - return cd; - -fail: - ath_dbg(common, DFS, - "failed to allocate channel_detector for freq=%d\n", freq); - channel_detector_exit(dpd, cd); - return NULL; -} - -/** - * channel_detector_get() - get channel detector for given frequency - * @param dpd instance pointer - * @param freq frequency in MHz - * @return pointer to channel detector on success, NULL otherwise - * - * Return existing channel detector for the given frequency or return a - * newly create one. - */ -static struct channel_detector * -channel_detector_get(struct dfs_pattern_detector *dpd, u16 freq) -{ - struct channel_detector *cd; - list_for_each_entry(cd, &dpd->channel_detectors, head) { - if (cd->freq == freq) - return cd; - } - return channel_detector_create(dpd, freq); -} - -/* - * DFS Pattern Detector - */ - -/* dpd_reset(): reset all channel detectors */ -static void dpd_reset(struct dfs_pattern_detector *dpd) -{ - struct channel_detector *cd; - if (!list_empty(&dpd->channel_detectors)) - list_for_each_entry(cd, &dpd->channel_detectors, head) - channel_detector_reset(dpd, cd); - -} -static void dpd_exit(struct dfs_pattern_detector *dpd) -{ - struct channel_detector *cd, *cd0; - if (!list_empty(&dpd->channel_detectors)) - list_for_each_entry_safe(cd, cd0, &dpd->channel_detectors, head) - channel_detector_exit(dpd, cd); - kfree(dpd); -} - -static bool -dpd_add_pulse(struct dfs_pattern_detector *dpd, struct pulse_event *event) -{ - u32 i; - struct channel_detector *cd; - - /* - * pulses received for a non-supported or un-initialized - * domain are treated as detected radars for fail-safety - */ - if (dpd->region == NL80211_DFS_UNSET) - return true; - - cd = channel_detector_get(dpd, event->freq); - if (cd == NULL) - return false; - - dpd->last_pulse_ts = event->ts; - /* reset detector on time stamp wraparound, caused by TSF reset */ - if (event->ts < dpd->last_pulse_ts) - dpd_reset(dpd); - - /* do type individual pattern matching */ - for (i = 0; i < dpd->num_radar_types; i++) { - struct pri_detector *pd = cd->detectors[i]; - struct pri_sequence *ps = pd->add_pulse(pd, event); - if (ps != NULL) { - ath_dbg(ath9k_hw_common(dpd->ah), DFS, - "DFS: radar found on freq=%d: id=%d, pri=%d, " - "count=%d, count_false=%d\n", - event->freq, pd->rs->type_id, - ps->pri, ps->count, ps->count_falses); - channel_detector_reset(dpd, cd); - return true; - } - } - return false; -} - -static bool dpd_set_domain(struct dfs_pattern_detector *dpd, - enum nl80211_dfs_regions region) -{ - const struct radar_types *rt; - struct channel_detector *cd, *cd0; - - if (dpd->region == region) - return true; - - dpd->region = NL80211_DFS_UNSET; - - rt = get_dfs_domain_radar_types(region); - if (rt == NULL) - return false; - - /* delete all channel detectors for previous DFS domain */ - if (!list_empty(&dpd->channel_detectors)) - list_for_each_entry_safe(cd, cd0, &dpd->channel_detectors, head) - channel_detector_exit(dpd, cd); - dpd->radar_spec = rt->radar_types; - dpd->num_radar_types = rt->num_radar_types; - - dpd->region = region; - return true; -} - -static struct dfs_pattern_detector default_dpd = { - .exit = dpd_exit, - .set_dfs_domain = dpd_set_domain, - .add_pulse = dpd_add_pulse, - .region = NL80211_DFS_UNSET, -}; - -struct dfs_pattern_detector * -dfs_pattern_detector_init(struct ath_hw *ah, enum nl80211_dfs_regions region) -{ - struct dfs_pattern_detector *dpd; - struct ath_common *common = ath9k_hw_common(ah); - - dpd = kmalloc(sizeof(*dpd), GFP_KERNEL); - if (dpd == NULL) - return NULL; - - *dpd = default_dpd; - INIT_LIST_HEAD(&dpd->channel_detectors); - - dpd->ah = ah; - if (dpd->set_dfs_domain(dpd, region)) - return dpd; - - ath_dbg(common, DFS,"Could not set DFS domain to %d", region); - kfree(dpd); - return NULL; -} -EXPORT_SYMBOL(dfs_pattern_detector_init); diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h deleted file mode 100644 index 90a5abcc4265..000000000000 --- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2012 Neratec Solutions AG - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef DFS_PATTERN_DETECTOR_H -#define DFS_PATTERN_DETECTOR_H - -#include <linux/types.h> -#include <linux/list.h> -#include <linux/nl80211.h> - -/** - * struct pulse_event - describing pulses reported by PHY - * @ts: pulse time stamp in us - * @freq: channel frequency in MHz - * @width: pulse duration in us - * @rssi: rssi of radar event - */ -struct pulse_event { - u64 ts; - u16 freq; - u8 width; - u8 rssi; -}; - -/** - * struct radar_detector_specs - detector specs for a radar pattern type - * @type_id: pattern type, as defined by regulatory - * @width_min: minimum radar pulse width in [us] - * @width_max: maximum radar pulse width in [us] - * @pri_min: minimum pulse repetition interval in [us] (including tolerance) - * @pri_max: minimum pri in [us] (including tolerance) - * @num_pri: maximum number of different pri for this type - * @ppb: pulses per bursts for this type - * @ppb_thresh: number of pulses required to trigger detection - * @max_pri_tolerance: pulse time stamp tolerance on both sides [us] - */ -struct radar_detector_specs { - u8 type_id; - u8 width_min; - u8 width_max; - u16 pri_min; - u16 pri_max; - u8 num_pri; - u8 ppb; - u8 ppb_thresh; - u8 max_pri_tolerance; -}; - -/** - * struct dfs_pattern_detector - DFS pattern detector - * @exit(): destructor - * @set_dfs_domain(): set DFS domain, resets detector lines upon domain changes - * @add_pulse(): add radar pulse to detector, returns true on detection - * @region: active DFS region, NL80211_DFS_UNSET until set - * @num_radar_types: number of different radar types - * @last_pulse_ts: time stamp of last valid pulse in usecs - * @radar_detector_specs: array of radar detection specs - * @channel_detectors: list connecting channel_detector elements - */ -struct dfs_pattern_detector { - void (*exit)(struct dfs_pattern_detector *dpd); - bool (*set_dfs_domain)(struct dfs_pattern_detector *dpd, - enum nl80211_dfs_regions region); - bool (*add_pulse)(struct dfs_pattern_detector *dpd, - struct pulse_event *pe); - - enum nl80211_dfs_regions region; - u8 num_radar_types; - u64 last_pulse_ts; - /* needed for ath_dbg() */ - struct ath_hw *ah; - - const struct radar_detector_specs *radar_spec; - struct list_head channel_detectors; -}; - -/** - * dfs_pattern_detector_init() - constructor for pattern detector class - * @param region: DFS domain to be used, can be NL80211_DFS_UNSET at creation - * @return instance pointer on success, NULL otherwise - */ -#if defined(CONFIG_ATH9K_DFS_CERTIFIED) -extern struct dfs_pattern_detector * -dfs_pattern_detector_init(struct ath_hw *ah, enum nl80211_dfs_regions region); -#else -static inline struct dfs_pattern_detector * -dfs_pattern_detector_init(struct ath_hw *ah, enum nl80211_dfs_regions region) -{ - return NULL; -} -#endif /* CONFIG_ATH9K_DFS_CERTIFIED */ - -#endif /* DFS_PATTERN_DETECTOR_H */ diff --git a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c deleted file mode 100644 index 5ba4b6fe37c0..000000000000 --- a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright (c) 2012 Neratec Solutions AG - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/slab.h> -#include <linux/spinlock.h> - -#include "ath9k.h" -#include "dfs_pattern_detector.h" -#include "dfs_pri_detector.h" -#include "dfs_debug.h" - -/** - * struct pulse_elem - elements in pulse queue - * @ts: time stamp in usecs - */ -struct pulse_elem { - struct list_head head; - u64 ts; -}; - -/** - * pde_get_multiple() - get number of multiples considering a given tolerance - * @return factor if abs(val - factor*fraction) <= tolerance, 0 otherwise - */ -static u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance) -{ - u32 remainder; - u32 factor; - u32 delta; - - if (fraction == 0) - return 0; - - delta = (val < fraction) ? (fraction - val) : (val - fraction); - - if (delta <= tolerance) - /* val and fraction are within tolerance */ - return 1; - - factor = val / fraction; - remainder = val % fraction; - if (remainder > tolerance) { - /* no exact match */ - if ((fraction - remainder) <= tolerance) - /* remainder is within tolerance */ - factor++; - else - factor = 0; - } - return factor; -} - -/** - * DOC: Singleton Pulse and Sequence Pools - * - * Instances of pri_sequence and pulse_elem are kept in singleton pools to - * reduce the number of dynamic allocations. They are shared between all - * instances and grow up to the peak number of simultaneously used objects. - * - * Memory is freed after all references to the pools are released. - */ -static u32 singleton_pool_references; -static LIST_HEAD(pulse_pool); -static LIST_HEAD(pseq_pool); -static DEFINE_SPINLOCK(pool_lock); - -static void pool_register_ref(void) -{ - spin_lock_bh(&pool_lock); - singleton_pool_references++; - DFS_POOL_STAT_INC(pool_reference); - spin_unlock_bh(&pool_lock); -} - -static void pool_deregister_ref(void) -{ - spin_lock_bh(&pool_lock); - singleton_pool_references--; - DFS_POOL_STAT_DEC(pool_reference); - if (singleton_pool_references == 0) { - /* free singleton pools with no references left */ - struct pri_sequence *ps, *ps0; - struct pulse_elem *p, *p0; - - list_for_each_entry_safe(p, p0, &pulse_pool, head) { - list_del(&p->head); - DFS_POOL_STAT_DEC(pulse_allocated); - kfree(p); - } - list_for_each_entry_safe(ps, ps0, &pseq_pool, head) { - list_del(&ps->head); - DFS_POOL_STAT_DEC(pseq_allocated); - kfree(ps); - } - } - spin_unlock_bh(&pool_lock); -} - -static void pool_put_pulse_elem(struct pulse_elem *pe) -{ - spin_lock_bh(&pool_lock); - list_add(&pe->head, &pulse_pool); - DFS_POOL_STAT_DEC(pulse_used); - spin_unlock_bh(&pool_lock); -} - -static void pool_put_pseq_elem(struct pri_sequence *pse) -{ - spin_lock_bh(&pool_lock); - list_add(&pse->head, &pseq_pool); - DFS_POOL_STAT_DEC(pseq_used); - spin_unlock_bh(&pool_lock); -} - -static struct pri_sequence *pool_get_pseq_elem(void) -{ - struct pri_sequence *pse = NULL; - spin_lock_bh(&pool_lock); - if (!list_empty(&pseq_pool)) { - pse = list_first_entry(&pseq_pool, struct pri_sequence, head); - list_del(&pse->head); - DFS_POOL_STAT_INC(pseq_used); - } - spin_unlock_bh(&pool_lock); - return pse; -} - -static struct pulse_elem *pool_get_pulse_elem(void) -{ - struct pulse_elem *pe = NULL; - spin_lock_bh(&pool_lock); - if (!list_empty(&pulse_pool)) { - pe = list_first_entry(&pulse_pool, struct pulse_elem, head); - list_del(&pe->head); - DFS_POOL_STAT_INC(pulse_used); - } - spin_unlock_bh(&pool_lock); - return pe; -} - -static struct pulse_elem *pulse_queue_get_tail(struct pri_detector *pde) -{ - struct list_head *l = &pde->pulses; - if (list_empty(l)) - return NULL; - return list_entry(l->prev, struct pulse_elem, head); -} - -static bool pulse_queue_dequeue(struct pri_detector *pde) -{ - struct pulse_elem *p = pulse_queue_get_tail(pde); - if (p != NULL) { - list_del_init(&p->head); - pde->count--; - /* give it back to pool */ - pool_put_pulse_elem(p); - } - return (pde->count > 0); -} - -/* remove pulses older than window */ -static void pulse_queue_check_window(struct pri_detector *pde) -{ - u64 min_valid_ts; - struct pulse_elem *p; - - /* there is no delta time with less than 2 pulses */ - if (pde->count < 2) - return; - - if (pde->last_ts <= pde->window_size) - return; - - min_valid_ts = pde->last_ts - pde->window_size; - while ((p = pulse_queue_get_tail(pde)) != NULL) { - if (p->ts >= min_valid_ts) - return; - pulse_queue_dequeue(pde); - } -} - -static bool pulse_queue_enqueue(struct pri_detector *pde, u64 ts) -{ - struct pulse_elem *p = pool_get_pulse_elem(); - if (p == NULL) { - p = kmalloc(sizeof(*p), GFP_ATOMIC); - if (p == NULL) { - DFS_POOL_STAT_INC(pulse_alloc_error); - return false; - } - DFS_POOL_STAT_INC(pulse_allocated); - DFS_POOL_STAT_INC(pulse_used); - } - INIT_LIST_HEAD(&p->head); - p->ts = ts; - list_add(&p->head, &pde->pulses); - pde->count++; - pde->last_ts = ts; - pulse_queue_check_window(pde); - if (pde->count >= pde->max_count) - pulse_queue_dequeue(pde); - return true; -} - -static bool pseq_handler_create_sequences(struct pri_detector *pde, - u64 ts, u32 min_count) -{ - struct pulse_elem *p; - list_for_each_entry(p, &pde->pulses, head) { - struct pri_sequence ps, *new_ps; - struct pulse_elem *p2; - u32 tmp_false_count; - u64 min_valid_ts; - u32 delta_ts = ts - p->ts; - - if (delta_ts < pde->rs->pri_min) - /* ignore too small pri */ - continue; - - if (delta_ts > pde->rs->pri_max) - /* stop on too large pri (sorted list) */ - break; - - /* build a new sequence with new potential pri */ - ps.count = 2; - ps.count_falses = 0; - ps.first_ts = p->ts; - ps.last_ts = ts; - ps.pri = ts - p->ts; - ps.dur = ps.pri * (pde->rs->ppb - 1) - + 2 * pde->rs->max_pri_tolerance; - - p2 = p; - tmp_false_count = 0; - min_valid_ts = ts - ps.dur; - /* check which past pulses are candidates for new sequence */ - list_for_each_entry_continue(p2, &pde->pulses, head) { - u32 factor; - if (p2->ts < min_valid_ts) - /* stop on crossing window border */ - break; - /* check if pulse match (multi)PRI */ - factor = pde_get_multiple(ps.last_ts - p2->ts, ps.pri, - pde->rs->max_pri_tolerance); - if (factor > 0) { - ps.count++; - ps.first_ts = p2->ts; - /* - * on match, add the intermediate falses - * and reset counter - */ - ps.count_falses += tmp_false_count; - tmp_false_count = 0; - } else { - /* this is a potential false one */ - tmp_false_count++; - } - } - if (ps.count < min_count) - /* did not reach minimum count, drop sequence */ - continue; - - /* this is a valid one, add it */ - ps.deadline_ts = ps.first_ts + ps.dur; - new_ps = pool_get_pseq_elem(); - if (new_ps == NULL) { - new_ps = kmalloc(sizeof(*new_ps), GFP_ATOMIC); - if (new_ps == NULL) { - DFS_POOL_STAT_INC(pseq_alloc_error); - return false; - } - DFS_POOL_STAT_INC(pseq_allocated); - DFS_POOL_STAT_INC(pseq_used); - } - memcpy(new_ps, &ps, sizeof(ps)); - INIT_LIST_HEAD(&new_ps->head); - list_add(&new_ps->head, &pde->sequences); - } - return true; -} - -/* check new ts and add to all matching existing sequences */ -static u32 -pseq_handler_add_to_existing_seqs(struct pri_detector *pde, u64 ts) -{ - u32 max_count = 0; - struct pri_sequence *ps, *ps2; - list_for_each_entry_safe(ps, ps2, &pde->sequences, head) { - u32 delta_ts; - u32 factor; - - /* first ensure that sequence is within window */ - if (ts > ps->deadline_ts) { - list_del_init(&ps->head); - pool_put_pseq_elem(ps); - continue; - } - - delta_ts = ts - ps->last_ts; - factor = pde_get_multiple(delta_ts, ps->pri, - pde->rs->max_pri_tolerance); - if (factor > 0) { - ps->last_ts = ts; - ps->count++; - - if (max_count < ps->count) - max_count = ps->count; - } else { - ps->count_falses++; - } - } - return max_count; -} - -static struct pri_sequence * -pseq_handler_check_detection(struct pri_detector *pde) -{ - struct pri_sequence *ps; - - if (list_empty(&pde->sequences)) - return NULL; - - list_for_each_entry(ps, &pde->sequences, head) { - /* - * we assume to have enough matching confidence if we - * 1) have enough pulses - * 2) have more matching than false pulses - */ - if ((ps->count >= pde->rs->ppb_thresh) && - (ps->count * pde->rs->num_pri >= ps->count_falses)) - return ps; - } - return NULL; -} - - -/* free pulse queue and sequences list and give objects back to pools */ -static void pri_detector_reset(struct pri_detector *pde, u64 ts) -{ - struct pri_sequence *ps, *ps0; - struct pulse_elem *p, *p0; - list_for_each_entry_safe(ps, ps0, &pde->sequences, head) { - list_del_init(&ps->head); - pool_put_pseq_elem(ps); - } - list_for_each_entry_safe(p, p0, &pde->pulses, head) { - list_del_init(&p->head); - pool_put_pulse_elem(p); - } - pde->count = 0; - pde->last_ts = ts; -} - -static void pri_detector_exit(struct pri_detector *de) -{ - pri_detector_reset(de, 0); - pool_deregister_ref(); - kfree(de); -} - -static struct pri_sequence *pri_detector_add_pulse(struct pri_detector *de, - struct pulse_event *event) -{ - u32 max_updated_seq; - struct pri_sequence *ps; - u64 ts = event->ts; - const struct radar_detector_specs *rs = de->rs; - - /* ignore pulses not within width range */ - if ((rs->width_min > event->width) || (rs->width_max < event->width)) - return NULL; - - if ((ts - de->last_ts) < rs->max_pri_tolerance) - /* if delta to last pulse is too short, don't use this pulse */ - return NULL; - de->last_ts = ts; - - max_updated_seq = pseq_handler_add_to_existing_seqs(de, ts); - - if (!pseq_handler_create_sequences(de, ts, max_updated_seq)) { - pri_detector_reset(de, ts); - return false; - } - - ps = pseq_handler_check_detection(de); - - if (ps == NULL) - pulse_queue_enqueue(de, ts); - - return ps; -} - -struct pri_detector *pri_detector_init(const struct radar_detector_specs *rs) -{ - struct pri_detector *de; - - de = kzalloc(sizeof(*de), GFP_ATOMIC); - if (de == NULL) - return NULL; - de->exit = pri_detector_exit; - de->add_pulse = pri_detector_add_pulse; - de->reset = pri_detector_reset; - - INIT_LIST_HEAD(&de->sequences); - INIT_LIST_HEAD(&de->pulses); - de->window_size = rs->pri_max * rs->ppb * rs->num_pri; - de->max_count = rs->ppb * 2; - de->rs = rs; - - pool_register_ref(); - return de; -} diff --git a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h deleted file mode 100644 index 723962d1abc6..000000000000 --- a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2012 Neratec Solutions AG - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef DFS_PRI_DETECTOR_H -#define DFS_PRI_DETECTOR_H - -#include <linux/list.h> - -/** - * struct pri_sequence - sequence of pulses matching one PRI - * @head: list_head - * @pri: pulse repetition interval (PRI) in usecs - * @dur: duration of sequence in usecs - * @count: number of pulses in this sequence - * @count_falses: number of not matching pulses in this sequence - * @first_ts: time stamp of first pulse in usecs - * @last_ts: time stamp of last pulse in usecs - * @deadline_ts: deadline when this sequence becomes invalid (first_ts + dur) - */ -struct pri_sequence { - struct list_head head; - u32 pri; - u32 dur; - u32 count; - u32 count_falses; - u64 first_ts; - u64 last_ts; - u64 deadline_ts; -}; - -/** - * struct pri_detector - PRI detector element for a dedicated radar type - * @exit(): destructor - * @add_pulse(): add pulse event, returns pri_sequence if pattern was detected - * @reset(): clear states and reset to given time stamp - * @rs: detector specs for this detector element - * @last_ts: last pulse time stamp considered for this element in usecs - * @sequences: list_head holding potential pulse sequences - * @pulses: list connecting pulse_elem objects - * @count: number of pulses in queue - * @max_count: maximum number of pulses to be queued - * @window_size: window size back from newest pulse time stamp in usecs - */ -struct pri_detector { - void (*exit) (struct pri_detector *de); - struct pri_sequence * - (*add_pulse)(struct pri_detector *de, struct pulse_event *e); - void (*reset) (struct pri_detector *de, u64 ts); - -/* private: internal use only */ - const struct radar_detector_specs *rs; - u64 last_ts; - struct list_head sequences; - struct list_head pulses; - u32 count; - u32 max_count; - u32 window_size; -}; - -struct pri_detector *pri_detector_init(const struct radar_detector_specs *rs); - -#endif /* DFS_PRI_DETECTOR_H */ diff --git a/drivers/net/wireless/ath/ath9k/dynack.c b/drivers/net/wireless/ath/ath9k/dynack.c new file mode 100644 index 000000000000..598b3a2ad818 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/dynack.c @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2014, Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/export.h> +#include "ath9k.h" +#include "hw.h" +#include "dynack.h" + +#define COMPUTE_TO (5 * HZ) +#define LATEACK_DELAY (10 * HZ) +#define EWMA_LEVEL 96 +#define EWMA_DIV 128 + +/** + * ath_dynack_get_max_to - set max timeout according to channel width + * @ah: ath hw + * + */ +static u32 ath_dynack_get_max_to(struct ath_hw *ah) +{ + const struct ath9k_channel *chan = ah->curchan; + + if (!chan) + return 300; + + if (IS_CHAN_HT40(chan)) + return 300; + if (IS_CHAN_HALF_RATE(chan)) + return 750; + if (IS_CHAN_QUARTER_RATE(chan)) + return 1500; + return 600; +} + +/* + * ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation + */ +static inline int ath_dynack_ewma(int old, int new) +{ + if (old > 0) + return (new * (EWMA_DIV - EWMA_LEVEL) + + old * EWMA_LEVEL) / EWMA_DIV; + else + return new; +} + +/** + * ath_dynack_get_sifs - get sifs time based on phy used + * @ah: ath hw + * @phy: phy used + * + */ +static inline u32 ath_dynack_get_sifs(struct ath_hw *ah, int phy) +{ + u32 sifs = CCK_SIFS_TIME; + + if (phy == WLAN_RC_PHY_OFDM) { + if (IS_CHAN_QUARTER_RATE(ah->curchan)) + sifs = OFDM_SIFS_TIME_QUARTER; + else if (IS_CHAN_HALF_RATE(ah->curchan)) + sifs = OFDM_SIFS_TIME_HALF; + else + sifs = OFDM_SIFS_TIME; + } + return sifs; +} + +/** + * ath_dynack_bssidmask - filter out ACK frames based on BSSID mask + * @ah: ath hw + * @mac: receiver address + */ +static inline bool ath_dynack_bssidmask(struct ath_hw *ah, const u8 *mac) +{ + int i; + struct ath_common *common = ath9k_hw_common(ah); + + for (i = 0; i < ETH_ALEN; i++) { + if ((common->macaddr[i] & common->bssidmask[i]) != + (mac[i] & common->bssidmask[i])) + return false; + } + + return true; +} + +/** + * ath_dynack_set_timeout - configure timeouts/slottime registers + * @ah: ath hw + * @to: timeout value + * + */ +static void ath_dynack_set_timeout(struct ath_hw *ah, int to) +{ + struct ath_common *common = ath9k_hw_common(ah); + int slottime = (to - 3) / 2; + + ath_dbg(common, DYNACK, "ACK timeout %u slottime %u\n", + to, slottime); + ath9k_hw_setslottime(ah, slottime); + ath9k_hw_set_ack_timeout(ah, to); + ath9k_hw_set_cts_timeout(ah, to); +} + +/** + * ath_dynack_compute_ackto - compute ACK timeout as the maximum STA timeout + * @ah: ath hw + * + * should be called while holding qlock + */ +static void ath_dynack_compute_ackto(struct ath_hw *ah) +{ + struct ath_dynack *da = &ah->dynack; + struct ath_node *an; + int to = 0; + + list_for_each_entry(an, &da->nodes, list) + if (an->ackto > to) + to = an->ackto; + + if (to && da->ackto != to) { + ath_dynack_set_timeout(ah, to); + da->ackto = to; + } +} + +/** + * ath_dynack_compute_to - compute STA ACK timeout + * @ah: ath hw + * + * should be called while holding qlock + */ +static void ath_dynack_compute_to(struct ath_hw *ah) +{ + struct ath_dynack *da = &ah->dynack; + u32 ackto, ack_ts, max_to; + struct ieee80211_sta *sta; + struct ts_info *st_ts; + struct ath_node *an; + u8 *dst, *src; + + rcu_read_lock(); + + max_to = ath_dynack_get_max_to(ah); + while (da->st_rbf.h_rb != da->st_rbf.t_rb && + da->ack_rbf.h_rb != da->ack_rbf.t_rb) { + ack_ts = da->ack_rbf.tstamp[da->ack_rbf.h_rb]; + st_ts = &da->st_rbf.ts[da->st_rbf.h_rb]; + dst = da->st_rbf.addr[da->st_rbf.h_rb].h_dest; + src = da->st_rbf.addr[da->st_rbf.h_rb].h_src; + + ath_dbg(ath9k_hw_common(ah), DYNACK, + "ack_ts %u st_ts %u st_dur %u [%u-%u]\n", + ack_ts, st_ts->tstamp, st_ts->dur, + da->ack_rbf.h_rb, da->st_rbf.h_rb); + + if (ack_ts > st_ts->tstamp + st_ts->dur) { + ackto = ack_ts - st_ts->tstamp - st_ts->dur; + + if (ackto < max_to) { + sta = ieee80211_find_sta_by_ifaddr(ah->hw, dst, + src); + if (sta) { + an = (struct ath_node *)sta->drv_priv; + an->ackto = ath_dynack_ewma(an->ackto, + ackto); + ath_dbg(ath9k_hw_common(ah), DYNACK, + "%pM to %d [%u]\n", dst, + an->ackto, ackto); + if (time_is_before_jiffies(da->lto)) { + ath_dynack_compute_ackto(ah); + da->lto = jiffies + COMPUTE_TO; + } + } + INCR(da->ack_rbf.h_rb, ATH_DYN_BUF); + } + INCR(da->st_rbf.h_rb, ATH_DYN_BUF); + } else { + INCR(da->ack_rbf.h_rb, ATH_DYN_BUF); + } + } + + rcu_read_unlock(); +} + +/** + * ath_dynack_sample_tx_ts - status timestamp sampling method + * @ah: ath hw + * @skb: socket buffer + * @ts: tx status info + * @sta: station pointer + * + */ +void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb, + struct ath_tx_status *ts, + struct ieee80211_sta *sta) +{ + struct ieee80211_hdr *hdr; + struct ath_dynack *da = &ah->dynack; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + u32 dur = ts->duration; + u8 ridx; + + if (!da->enabled || (info->flags & IEEE80211_TX_CTL_NO_ACK)) + return; + + spin_lock_bh(&da->qlock); + + hdr = (struct ieee80211_hdr *)skb->data; + + /* late ACK */ + if (ts->ts_status & ATH9K_TXERR_XRETRY) { + if (ieee80211_is_assoc_req(hdr->frame_control) || + ieee80211_is_assoc_resp(hdr->frame_control) || + ieee80211_is_auth(hdr->frame_control)) { + u32 max_to = ath_dynack_get_max_to(ah); + + ath_dbg(common, DYNACK, "late ack\n"); + ath_dynack_set_timeout(ah, max_to); + if (sta) { + struct ath_node *an; + + an = (struct ath_node *)sta->drv_priv; + an->ackto = -1; + } + da->lto = jiffies + LATEACK_DELAY; + } + + spin_unlock_bh(&da->qlock); + return; + } + + ridx = ts->ts_rateindex; + + da->st_rbf.ts[da->st_rbf.t_rb].tstamp = ts->ts_tstamp; + + /* ether_addr_copy() gives a false warning on gcc-10 so use memcpy() + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97490 + */ + memcpy(da->st_rbf.addr[da->st_rbf.t_rb].h_dest, hdr->addr1, ETH_ALEN); + memcpy(da->st_rbf.addr[da->st_rbf.t_rb].h_src, hdr->addr2, ETH_ALEN); + + if (!(info->status.rates[ridx].flags & IEEE80211_TX_RC_MCS)) { + const struct ieee80211_rate *rate; + struct ieee80211_tx_rate *rates = info->status.rates; + u32 phy; + + rate = &common->sbands[info->band].bitrates[rates[ridx].idx]; + if (info->band == NL80211_BAND_2GHZ && + !(rate->flags & IEEE80211_RATE_ERP_G)) + phy = WLAN_RC_PHY_CCK; + else + phy = WLAN_RC_PHY_OFDM; + + dur -= ath_dynack_get_sifs(ah, phy); + } + da->st_rbf.ts[da->st_rbf.t_rb].dur = dur; + + INCR(da->st_rbf.t_rb, ATH_DYN_BUF); + if (da->st_rbf.t_rb == da->st_rbf.h_rb) + INCR(da->st_rbf.h_rb, ATH_DYN_BUF); + + ath_dbg(common, DYNACK, "{%pM} tx sample %u [dur %u][h %u-t %u]\n", + hdr->addr1, ts->ts_tstamp, dur, da->st_rbf.h_rb, + da->st_rbf.t_rb); + + ath_dynack_compute_to(ah); + + spin_unlock_bh(&da->qlock); +} +EXPORT_SYMBOL(ath_dynack_sample_tx_ts); + +/** + * ath_dynack_sample_ack_ts - ACK timestamp sampling method + * @ah: ath hw + * @skb: socket buffer + * @ts: rx timestamp + * + */ +void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb, + u32 ts) +{ + struct ath_dynack *da = &ah->dynack; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (!da->enabled || !ath_dynack_bssidmask(ah, hdr->addr1)) + return; + + spin_lock_bh(&da->qlock); + da->ack_rbf.tstamp[da->ack_rbf.t_rb] = ts; + + INCR(da->ack_rbf.t_rb, ATH_DYN_BUF); + if (da->ack_rbf.t_rb == da->ack_rbf.h_rb) + INCR(da->ack_rbf.h_rb, ATH_DYN_BUF); + + ath_dbg(common, DYNACK, "rx sample %u [h %u-t %u]\n", + ts, da->ack_rbf.h_rb, da->ack_rbf.t_rb); + + ath_dynack_compute_to(ah); + + spin_unlock_bh(&da->qlock); +} +EXPORT_SYMBOL(ath_dynack_sample_ack_ts); + +/** + * ath_dynack_node_init - init ath_node related info + * @ah: ath hw + * @an: ath node + * + */ +void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an) +{ + struct ath_dynack *da = &ah->dynack; + + an->ackto = da->ackto; + + spin_lock_bh(&da->qlock); + list_add_tail(&an->list, &da->nodes); + spin_unlock_bh(&da->qlock); +} +EXPORT_SYMBOL(ath_dynack_node_init); + +/** + * ath_dynack_node_deinit - deinit ath_node related info + * @ah: ath hw + * @an: ath node + * + */ +void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an) +{ + struct ath_dynack *da = &ah->dynack; + + spin_lock_bh(&da->qlock); + list_del(&an->list); + spin_unlock_bh(&da->qlock); +} +EXPORT_SYMBOL(ath_dynack_node_deinit); + +/** + * ath_dynack_reset - reset dynack processing + * @ah: ath hw + * + */ +void ath_dynack_reset(struct ath_hw *ah) +{ + struct ath_dynack *da = &ah->dynack; + struct ath_node *an; + + spin_lock_bh(&da->qlock); + + da->lto = jiffies + COMPUTE_TO; + + da->st_rbf.t_rb = 0; + da->st_rbf.h_rb = 0; + da->ack_rbf.t_rb = 0; + da->ack_rbf.h_rb = 0; + + da->ackto = ath_dynack_get_max_to(ah); + list_for_each_entry(an, &da->nodes, list) + an->ackto = da->ackto; + + /* init acktimeout */ + ath_dynack_set_timeout(ah, da->ackto); + + spin_unlock_bh(&da->qlock); +} +EXPORT_SYMBOL(ath_dynack_reset); + +/** + * ath_dynack_init - init dynack data structure + * @ah: ath hw + * + */ +void ath_dynack_init(struct ath_hw *ah) +{ + struct ath_dynack *da = &ah->dynack; + + memset(da, 0, sizeof(struct ath_dynack)); + + spin_lock_init(&da->qlock); + INIT_LIST_HEAD(&da->nodes); + /* ackto = slottime + sifs + air delay */ + da->ackto = 9 + 16 + 64; + + ah->hw->wiphy->features |= NL80211_FEATURE_ACKTO_ESTIMATION; +} diff --git a/drivers/net/wireless/ath/ath9k/dynack.h b/drivers/net/wireless/ath/ath9k/dynack.h new file mode 100644 index 000000000000..cf60224d40df --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/dynack.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DYNACK_H +#define DYNACK_H + +#define ATH_DYN_BUF 64 + +struct ath_hw; +struct ath_node; + +/** + * struct ath_dyn_rxbuf - ACK frame ring buffer + * @h_rb: ring buffer head + * @t_rb: ring buffer tail + * @tstamp: ACK RX timestamp buffer + */ +struct ath_dyn_rxbuf { + u16 h_rb, t_rb; + u32 tstamp[ATH_DYN_BUF]; +}; + +struct ts_info { + u32 tstamp; + u32 dur; +}; + +struct haddr_pair { + u8 h_dest[ETH_ALEN]; + u8 h_src[ETH_ALEN]; +}; + +/** + * struct ath_dyn_txbuf - tx frame ring buffer + * @h_rb: ring buffer head + * @t_rb: ring buffer tail + * @addr: dest/src address pair for a given TX frame + * @ts: TX frame timestamp buffer + */ +struct ath_dyn_txbuf { + u16 h_rb, t_rb; + struct haddr_pair addr[ATH_DYN_BUF]; + struct ts_info ts[ATH_DYN_BUF]; +}; + +/** + * struct ath_dynack - dynack processing info + * @enabled: enable dyn ack processing + * @ackto: current ACK timeout + * @lto: last ACK timeout computation + * @nodes: ath_node linked list + * @qlock: ts queue spinlock + * @ack_rbf: ACK ts ring buffer + * @st_rbf: status ts ring buffer + */ +struct ath_dynack { + bool enabled; + int ackto; + unsigned long lto; + + struct list_head nodes; + + /* protect timestamp queue access */ + spinlock_t qlock; + struct ath_dyn_rxbuf ack_rbf; + struct ath_dyn_txbuf st_rbf; +}; + +#if defined(CONFIG_ATH9K_DYNACK) +void ath_dynack_reset(struct ath_hw *ah); +void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an); +void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an); +void ath_dynack_init(struct ath_hw *ah); +void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb, u32 ts); +void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb, + struct ath_tx_status *ts, + struct ieee80211_sta *sta); +#else +static inline void ath_dynack_init(struct ath_hw *ah) {} +static inline void ath_dynack_node_init(struct ath_hw *ah, + struct ath_node *an) {} +static inline void ath_dynack_node_deinit(struct ath_hw *ah, + struct ath_node *an) {} +static inline void ath_dynack_sample_ack_ts(struct ath_hw *ah, + struct sk_buff *skb, u32 ts) {} +static inline void ath_dynack_sample_tx_ts(struct ath_hw *ah, + struct sk_buff *skb, + struct ath_tx_status *ts, + struct ieee80211_sta *sta) {} +#endif + +#endif /* DYNACK_H */ diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 971d770722cf..df58dc02e104 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -27,12 +27,7 @@ void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val) void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask, u32 shift, u32 val) { - u32 regVal; - - regVal = REG_READ(ah, reg) & ~mask; - regVal |= (val << shift) & mask; - - REG_WRITE(ah, reg, regVal); + REG_RMW(ah, reg, ((val << shift) & mask), mask); if (ah->config.analog_shiftreg) udelay(100); @@ -113,26 +108,41 @@ void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, } } -static bool ath9k_hw_nvram_read_blob(struct ath_hw *ah, u32 off, - u16 *data) +static bool ath9k_hw_nvram_read_array(u16 *blob, size_t blob_size, + off_t offset, u16 *data) { - u16 *blob_data; - - if (off * sizeof(u16) > ah->eeprom_blob->size) + if (offset >= blob_size) return false; - blob_data = (u16 *)ah->eeprom_blob->data; - *data = blob_data[off]; + *data = blob[offset]; return true; } +static bool ath9k_hw_nvram_read_firmware(const struct firmware *eeprom_blob, + off_t offset, u16 *data) +{ + return ath9k_hw_nvram_read_array((u16 *) eeprom_blob->data, + eeprom_blob->size / sizeof(u16), + offset, data); +} + +static bool ath9k_hw_nvram_read_nvmem(struct ath_hw *ah, off_t offset, + u16 *data) +{ + return ath9k_hw_nvram_read_array(ah->nvmem_blob, + ah->nvmem_blob_len / sizeof(u16), + offset, data); +} + bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) { struct ath_common *common = ath9k_hw_common(ah); bool ret; - if (ah->eeprom_blob) - ret = ath9k_hw_nvram_read_blob(ah, off, data); + if (ah->nvmem_blob) + ret = ath9k_hw_nvram_read_nvmem(ah, off, data); + else if (ah->eeprom_blob) + ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data); else ret = common->bus_ops->eeprom_read(common, off, data); @@ -143,6 +153,90 @@ bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) return ret; } +int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size) +{ + u16 magic; + u16 *eepdata; + int i; + bool needs_byteswap = false; + struct ath_common *common = ath9k_hw_common(ah); + + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { + ath_err(common, "Reading Magic # failed\n"); + return -EIO; + } + + if (swab16(magic) == AR5416_EEPROM_MAGIC) { + needs_byteswap = true; + ath_dbg(common, EEPROM, + "EEPROM needs byte-swapping to correct endianness.\n"); + } else if (magic != AR5416_EEPROM_MAGIC) { + if (ath9k_hw_use_flash(ah)) { + ath_dbg(common, EEPROM, + "Ignoring invalid EEPROM magic (0x%04x).\n", + magic); + } else { + ath_err(common, + "Invalid EEPROM magic (0x%04x).\n", magic); + return -EINVAL; + } + } + + if (needs_byteswap) { + if (ah->ah_flags & AH_NO_EEP_SWAP) { + ath_info(common, + "Ignoring endianness difference in EEPROM magic bytes.\n"); + } else { + eepdata = (u16 *)(&ah->eeprom); + + for (i = 0; i < size; i++) + eepdata[i] = swab16(eepdata[i]); + } + } + + if (ah->eep_ops->get_eepmisc(ah) & AR5416_EEPMISC_BIG_ENDIAN) { + *swap_needed = true; + ath_dbg(common, EEPROM, + "Big Endian EEPROM detected according to EEPMISC register.\n"); + } else { + *swap_needed = false; + } + + return 0; +} + +bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size) +{ + u32 i, sum = 0; + u16 *eepdata = (u16 *)(&ah->eeprom); + struct ath_common *common = ath9k_hw_common(ah); + + for (i = 0; i < size; i++) + sum ^= eepdata[i]; + + if (sum != 0xffff) { + ath_err(common, "Bad EEPROM checksum 0x%x\n", sum); + return false; + } + + return true; +} + +bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (ah->eep_ops->get_eeprom_ver(ah) != version || + ah->eep_ops->get_eeprom_rev(ah) < minrev) { + ath_err(common, "Bad EEPROM VER 0x%04x or REV 0x%04x\n", + ah->eep_ops->get_eeprom_ver(ah), + ah->eep_ops->get_eeprom_rev(ah)); + return false; + } + + return true; +} + void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, u8 *pVpdList, u16 numIntercepts, u8 *pRetVpdList) @@ -332,7 +426,7 @@ u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit, else power_limit = 0; - return power_limit; + return min_t(u16, power_limit, MAX_RATE_POWER); } void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah) @@ -408,10 +502,9 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, if (match) { if (AR_SREV_9287(ah)) { - /* FIXME: array overrun? */ for (i = 0; i < numXpdGains; i++) { minPwrT4[i] = data_9287[idxL].pwrPdg[i][0]; - maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4]; + maxPwrT4[i] = data_9287[idxL].pwrPdg[i][intercepts - 1]; ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], data_9287[idxL].pwrPdg[i], data_9287[idxL].vpdPdg[i], @@ -421,7 +514,7 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, } else if (eeprom_4k) { for (i = 0; i < numXpdGains; i++) { minPwrT4[i] = data_4k[idxL].pwrPdg[i][0]; - maxPwrT4[i] = data_4k[idxL].pwrPdg[i][4]; + maxPwrT4[i] = data_4k[idxL].pwrPdg[i][intercepts - 1]; ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], data_4k[idxL].pwrPdg[i], data_4k[idxL].vpdPdg[i], @@ -431,7 +524,7 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, } else { for (i = 0; i < numXpdGains; i++) { minPwrT4[i] = data_def[idxL].pwrPdg[i][0]; - maxPwrT4[i] = data_def[idxL].pwrPdg[i][4]; + maxPwrT4[i] = data_def[idxL].pwrPdg[i][intercepts - 1]; ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], data_def[idxL].pwrPdg[i], data_def[idxL].vpdPdg[i], @@ -565,8 +658,6 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, int ath9k_hw_eeprom_init(struct ath_hw *ah) { - int status; - if (AR_SREV_9300_20_OR_LATER(ah)) ah->eep_ops = &eep_ar9300_ops; else if (AR_SREV_9287(ah)) { @@ -580,7 +671,5 @@ int ath9k_hw_eeprom_init(struct ath_hw *ah) if (!ah->eep_ops->fill_eeprom(ah)) return -EIO; - status = ah->eep_ops->check_eeprom(ah); - - return status; + return ah->eep_ops->check_eeprom(ah); } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 40d4f62d0f16..f1cde43fcb55 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -23,6 +23,17 @@ #include <net/cfg80211.h> #include "ar9003_eeprom.h" +/* helpers to swap EEPROM fields, which are stored as __le16 or __le32. Since + * we are 100% sure about it we __force these to u16/u32 for the swab calls to + * silence the sparse checks. These macros are used when we have a Big Endian + * EEPROM (according to AR5416_EEPMISC_BIG_ENDIAN) and need to convert the + * fields to __le16/__le32. + */ +#define EEPROM_FIELD_SWAB16(field) \ + (field = (__force __le16)swab16((__force u16)field)) +#define EEPROM_FIELD_SWAB32(field) \ + (field = (__force __le32)swab32((__force u32)field)) + #ifdef __BIG_ENDIAN #define AR5416_EEPROM_MAGIC 0x5aa5 #else @@ -57,8 +68,8 @@ #define AR5416_EEPROM_OFFSET 0x2000 #define AR5416_EEPROM_MAX 0xae0 -#define AR5416_EEPROM_START_ADDR \ - (AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200 +#define AR5416_EEPROM_START_ADDR(_ah) \ + (AR_SREV_9100(_ah)) ? 0x1fff1000 : 0x503f1200 #define SD_NO_CTL 0xE0 #define NO_CTL 0xff @@ -95,15 +106,14 @@ #define AR9285_RDEXT_DEFAULT 0x1F #define ATH9K_POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) -#define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) +#define FREQ2FBIN(x, y) (u8)((y) ? ((x) - 2300) : (((x) - 4800) / 5)) #define FBIN2FREQ(x, y) ((y) ? (2300 + x) : (4800 + 5 * x)) #define ath9k_hw_use_flash(_ah) (!(_ah->ah_flags & AH_USE_EEPROM)) -#define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) -#define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \ - ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) -#define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_11_OR_LATER(ah) && \ - ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) +#define OLC_FOR_AR9280_20_LATER(_ah) (AR_SREV_9280_20_OR_LATER(_ah) && \ + _ah->eep_ops->get_eeprom(_ah, EEP_OL_PWRCTRL)) +#define OLC_FOR_AR9287_10_LATER(_ah) (AR_SREV_9287_11_OR_LATER(_ah) && \ + _ah->eep_ops->get_eeprom(_ah, EEP_OL_PWRCTRL)) #define EEP_RFSILENT_ENABLED 0x0001 #define EEP_RFSILENT_ENABLED_S 0 @@ -121,6 +131,8 @@ #define AR5416_EEP_NO_BACK_VER 0x1 #define AR5416_EEP_VER 0xE +#define AR5416_EEP_VER_MAJOR_SHIFT 12 +#define AR5416_EEP_VER_MAJOR_MASK 0xF000 #define AR5416_EEP_VER_MINOR_MASK 0x0FFF #define AR5416_EEP_MINOR_VER_2 0x2 #define AR5416_EEP_MINOR_VER_3 0x3 @@ -161,6 +173,9 @@ #define AR5416_EEP_TXGAIN_ORIGINAL 0 #define AR5416_EEP_TXGAIN_HIGH_POWER 1 +/* Endianness of EEPROM content */ +#define AR5416_EEPMISC_BIG_ENDIAN 0x01 + #define AR5416_EEP4K_START_LOC 64 #define AR5416_EEP4K_NUM_2G_CAL_PIERS 3 #define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3 @@ -174,7 +189,6 @@ #define AR9280_TX_GAIN_TABLE_SIZE 22 #define AR9287_EEP_VER 0xE -#define AR9287_EEP_VER_MINOR_MASK 0xFFF #define AR9287_EEP_MINOR_VER_1 0x1 #define AR9287_EEP_MINOR_VER_2 0x2 #define AR9287_EEP_MINOR_VER_3 0x3 @@ -191,7 +205,6 @@ #define AR9287_NUM_CTLS 12 #define AR9287_NUM_BAND_EDGES 4 #define AR9287_PD_GAIN_ICEPTS 1 -#define AR9287_EEPMISC_BIG_ENDIAN 0x01 #define AR9287_EEPMISC_WOW 0x02 #define AR9287_MAX_CHAINS 2 #define AR9287_ANT_16S 32 @@ -228,7 +241,6 @@ enum eeprom_param { EEP_DB_5, EEP_OB_2, EEP_DB_2, - EEP_MINOR_REV, EEP_TX_MASK, EEP_RX_MASK, EEP_FSTCLK_5G, @@ -269,19 +281,19 @@ enum ath9k_hal_freq_band { }; struct base_eep_header { - u16 length; - u16 checksum; - u16 version; + __le16 length; + __le16 checksum; + __le16 version; u8 opCapFlags; u8 eepMisc; - u16 regDmn[2]; + __le16 regDmn[2]; u8 macAddr[6]; u8 rxMask; u8 txMask; - u16 rfSilent; - u16 blueToothOptions; - u16 deviceCap; - u32 binBuildNumber; + __le16 rfSilent; + __le16 blueToothOptions; + __le16 deviceCap; + __le32 binBuildNumber; u8 deviceType; u8 pwdclkind; u8 fastClk5g; @@ -299,33 +311,33 @@ struct base_eep_header { } __packed; struct base_eep_header_4k { - u16 length; - u16 checksum; - u16 version; + __le16 length; + __le16 checksum; + __le16 version; u8 opCapFlags; u8 eepMisc; - u16 regDmn[2]; + __le16 regDmn[2]; u8 macAddr[6]; u8 rxMask; u8 txMask; - u16 rfSilent; - u16 blueToothOptions; - u16 deviceCap; - u32 binBuildNumber; + __le16 rfSilent; + __le16 blueToothOptions; + __le16 deviceCap; + __le32 binBuildNumber; u8 deviceType; u8 txGainType; } __packed; struct spur_chan { - u16 spurChan; + __le16 spurChan; u8 spurRangeLow; u8 spurRangeHigh; } __packed; struct modal_eep_header { - u32 antCtrlChain[AR5416_MAX_CHAINS]; - u32 antCtrlCommon; + __le32 antCtrlChain[AR5416_MAX_CHAINS]; + __le32 antCtrlCommon; u8 antennaGainCh[AR5416_MAX_CHAINS]; u8 switchSettling; u8 txRxAttenCh[AR5416_MAX_CHAINS]; @@ -360,7 +372,7 @@ struct modal_eep_header { u8 db_ch1; u8 lna_ctl; u8 miscBits; - u16 xpaBiasLvlFreq[3]; + __le16 xpaBiasLvlFreq[3]; u8 futureModal[6]; struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS]; @@ -374,8 +386,8 @@ struct calDataPerFreqOpLoop { } __packed; struct modal_eep_4k_header { - u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; - u32 antCtrlCommon; + __le32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; + __le32 antCtrlCommon; u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS]; u8 switchSettling; u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS]; @@ -439,19 +451,19 @@ struct modal_eep_4k_header { } __packed; struct base_eep_ar9287_header { - u16 length; - u16 checksum; - u16 version; + __le16 length; + __le16 checksum; + __le16 version; u8 opCapFlags; u8 eepMisc; - u16 regDmn[2]; + __le16 regDmn[2]; u8 macAddr[6]; u8 rxMask; u8 txMask; - u16 rfSilent; - u16 blueToothOptions; - u16 deviceCap; - u32 binBuildNumber; + __le16 rfSilent; + __le16 blueToothOptions; + __le16 deviceCap; + __le32 binBuildNumber; u8 deviceType; u8 openLoopPwrCntl; int8_t pwrTableOffset; @@ -461,8 +473,8 @@ struct base_eep_ar9287_header { } __packed; struct modal_eep_ar9287_header { - u32 antCtrlChain[AR9287_MAX_CHAINS]; - u32 antCtrlCommon; + __le32 antCtrlChain[AR9287_MAX_CHAINS]; + __le32 antCtrlCommon; int8_t antennaGainCh[AR9287_MAX_CHAINS]; u8 switchSettling; u8 txRxAttenCh[AR9287_MAX_CHAINS]; @@ -653,6 +665,7 @@ struct eeprom_ops { u16 cfgCtl, u8 twiceAntennaReduction, u8 powerLimit, bool test); u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz); + u8 (*get_eepmisc)(struct ath_hw *ah); }; void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val); @@ -664,6 +677,9 @@ int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, u16 *indexL, u16 *indexR); bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data); +int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size); +bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size); +bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev); void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, int eep_start_loc, int size); void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index c2bfd748eed8..3e16cfe059f3 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -14,18 +14,23 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include "hw.h" #include "ar9002_phy.h" static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah) { - return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF); + u16 version = le16_to_cpu(ah->eeprom.map4k.baseEepHeader.version); + + return (version & AR5416_EEP_VER_MAJOR_MASK) >> + AR5416_EEP_VER_MAJOR_SHIFT; } static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) { - return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF); + u16 version = le16_to_cpu(ah->eeprom.map4k.baseEepHeader.version); + + return version & AR5416_EEP_VER_MINOR_MASK; } #define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) @@ -67,12 +72,12 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) return __ath9k_hw_4k_fill_eeprom(ah); } -#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS) +#ifdef CONFIG_ATH9K_COMMON_DEBUG static u32 ath9k_dump_4k_modal_eeprom(char *buf, u32 len, u32 size, struct modal_eep_4k_header *modal_hdr) { - PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]); - PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon); + PR_EEP("Chain0 Ant. Control", le32_to_cpu(modal_hdr->antCtrlChain[0])); + PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon)); PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]); PR_EEP("Switch Settle", modal_hdr->switchSettling); PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]); @@ -127,21 +132,22 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, { struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; struct base_eep_header_4k *pBase = &eep->baseEepHeader; + u32 binBuildNumber = le32_to_cpu(pBase->binBuildNumber); if (!dump_base_hdr) { - len += snprintf(buf + len, size - len, - "%20s :\n", "2GHz modal Header"); + len += scnprintf(buf + len, size - len, + "%20s :\n", "2GHz modal Header"); len = ath9k_dump_4k_modal_eeprom(buf, len, size, - &eep->modalHeader); + &eep->modalHeader); goto out; } - PR_EEP("Major Version", pBase->version >> 12); - PR_EEP("Minor Version", pBase->version & 0xFFF); - PR_EEP("Checksum", pBase->checksum); - PR_EEP("Length", pBase->length); - PR_EEP("RegDomain1", pBase->regDmn[0]); - PR_EEP("RegDomain2", pBase->regDmn[1]); + PR_EEP("Major Version", ath9k_hw_4k_get_eeprom_ver(ah)); + PR_EEP("Minor Version", ath9k_hw_4k_get_eeprom_rev(ah)); + PR_EEP("Checksum", le16_to_cpu(pBase->checksum)); + PR_EEP("Length", le16_to_cpu(pBase->length)); + PR_EEP("RegDomain1", le16_to_cpu(pBase->regDmn[0])); + PR_EEP("RegDomain2", le16_to_cpu(pBase->regDmn[1])); PR_EEP("TX Mask", pBase->txMask); PR_EEP("RX Mask", pBase->rxMask); PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); @@ -154,14 +160,14 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, AR5416_OPFLAGS_N_5G_HT20)); PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT40)); - PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01)); - PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF); - PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF); - PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF); + PR_EEP("Big Endian", !!(pBase->eepMisc & AR5416_EEPMISC_BIG_ENDIAN)); + PR_EEP("Cal Bin Major Ver", (binBuildNumber >> 24) & 0xFF); + PR_EEP("Cal Bin Minor Ver", (binBuildNumber >> 16) & 0xFF); + PR_EEP("Cal Bin Build", (binBuildNumber >> 8) & 0xFF); PR_EEP("TX Gain type", pBase->txGainType); - len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", - pBase->macAddr); + len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", + pBase->macAddr); out: if (len > size) @@ -177,132 +183,60 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, } #endif - -#undef SIZE_EEPROM_4K - static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) { -#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) - struct ath_common *common = ath9k_hw_common(ah); struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - u16 *eepdata, temp, magic, magic2; - u32 sum = 0, el; - bool need_swap = false; - int i, addr; - - - if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, - &magic)) { - ath_err(common, "Reading Magic # failed\n"); - return false; - } - - ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic); + u32 el; + bool need_swap; + int i, err; - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - need_swap = true; - eepdata = (u16 *) (&ah->eeprom); - - for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } else { - ath_err(common, - "Invalid EEPROM Magic. Endianness mismatch.\n"); - return -EINVAL; - } - } - } - - ath_dbg(common, EEPROM, "need_swap = %s\n", - need_swap ? "True" : "False"); + err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_4K); + if (err) + return err; if (need_swap) - el = swab16(ah->eeprom.map4k.baseEepHeader.length); - else - el = ah->eeprom.map4k.baseEepHeader.length; - - if (el > sizeof(struct ar5416_eeprom_4k)) - el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); + el = swab16((__force u16)eep->baseEepHeader.length); else - el = el / sizeof(u16); - - eepdata = (u16 *)(&ah->eeprom); + el = le16_to_cpu(eep->baseEepHeader.length); - for (i = 0; i < el; i++) - sum ^= *eepdata++; + el = min(el / sizeof(u16), SIZE_EEPROM_4K); + if (!ath9k_hw_nvram_validate_checksum(ah, el)) + return -EINVAL; if (need_swap) { - u32 integer; - u16 word; - - ath_dbg(common, EEPROM, - "EEPROM Endianness is not native.. Changing\n"); - - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; - - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; - - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; - - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; - - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; - - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; - - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; - - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; - - integer = swab32(eep->modalHeader.antCtrlCommon); - eep->modalHeader.antCtrlCommon = integer; - - for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { - integer = swab32(eep->modalHeader.antCtrlChain[i]); - eep->modalHeader.antCtrlChain[i] = integer; - } - - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - word = swab16(eep->modalHeader.spurChans[i].spurChan); - eep->modalHeader.spurChans[i].spurChan = word; - } + EEPROM_FIELD_SWAB16(eep->baseEepHeader.length); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.checksum); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.version); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[0]); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[1]); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.rfSilent); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.blueToothOptions); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.deviceCap); + EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlCommon); + + for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) + EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlChain[i]); + + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) + EEPROM_FIELD_SWAB16( + eep->modalHeader.spurChans[i].spurChan); } - if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || - ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); + if (!ath9k_hw_nvram_check_version(ah, AR5416_EEP_VER, + AR5416_EEP_NO_BACK_VER)) return -EINVAL; - } return 0; -#undef EEPROM_4K_SIZE } +#undef SIZE_EEPROM_4K + static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, enum eeprom_param param) { struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; struct modal_eep_4k_header *pModal = &eep->modalHeader; struct base_eep_header_4k *pBase = &eep->baseEepHeader; - u16 ver_minor; - - ver_minor = pBase->version & AR5416_EEP_VER_MINOR_MASK; switch (param) { case EEP_NFTHRESH_2: @@ -314,19 +248,17 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, case EEP_MAC_MSW: return get_unaligned_be16(pBase->macAddr + 4); case EEP_REG_0: - return pBase->regDmn[0]; + return le16_to_cpu(pBase->regDmn[0]); case EEP_OP_CAP: - return pBase->deviceCap; + return le16_to_cpu(pBase->deviceCap); case EEP_OP_MODE: return pBase->opCapFlags; case EEP_RF_SILENT: - return pBase->rfSilent; + return le16_to_cpu(pBase->rfSilent); case EEP_OB_2: return pModal->ob_0; case EEP_DB_2: return pModal->db1_1; - case EEP_MINOR_REV: - return ver_minor; case EEP_TX_MASK: return pBase->txMask; case EEP_RX_MASK: @@ -365,14 +297,12 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, xpdMask = pEepData->modalHeader.xpdGain; - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { + if (ath9k_hw_4k_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_2) pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; - } else { + else pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); - } pCalBChans = pEepData->calFreqPier2G; numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS; @@ -389,6 +319,7 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, } } + ENABLE_REG_RMW_BUFFER(ah); REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, (numXpdGain - 1) & 0x3); REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, @@ -396,6 +327,7 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, xpdGainValues[1]); REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0); + REG_RMW_BUFFER_FLUSH(ah); for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { regChainOffset = i * 0x1000; @@ -492,6 +424,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, ath9k_hw_get_channel_centers(ah, chan, ¢ers); scaledPower = powerLimit - antenna_reduction; + scaledPower = min_t(u16, scaledPower, MAX_RATE_POWER); numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; pCtlMode = ctlModesFor11g; @@ -656,10 +589,8 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, memset(ratesArray, 0, sizeof(ratesArray)); - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { + if (ath9k_hw_4k_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_2) ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - } ath9k_hw_set_4k_power_per_rate_table(ah, chan, &ratesArray[0], cfgCtl, @@ -748,6 +679,20 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } + /* TPC initializations */ + if (ah->tpc_enabled) { + int ht40_delta; + + ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0; + ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta); + /* Enable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, + MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE); + } else { + /* Disable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER); + } + REGWRITE_BUFFER_FLUSH(ah); } @@ -756,18 +701,16 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, struct ar5416_eeprom_4k *eep, u8 txRxAttenLocal) { - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0, - pModal->antCtrlChain[0]); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), - (REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & - ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); - - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { + ENABLE_REG_RMW_BUFFER(ah); + REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, + le32_to_cpu(pModal->antCtrlChain[0]), 0); + + REG_RMW(ah, AR_PHY_TIMING_CTRL4(0), + SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF), + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF); + + if (ath9k_hw_4k_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_3) { txRxAttenLocal = pModal->txRxAttenCh[0]; REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, @@ -803,6 +746,7 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + REG_RMW_BUFFER_FLUSH(ah); } /* @@ -812,6 +756,7 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, struct ath9k_channel *chan) { + struct ath9k_hw_capabilities *pCap = &ah->caps; struct modal_eep_4k_header *pModal; struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; struct base_eep_header_4k *pBase = &eep->baseEepHeader; @@ -824,7 +769,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, pModal = &eep->modalHeader; txRxAttenLocal = 23; - REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); + REG_WRITE(ah, AR_PHY_SWITCH_COM, le32_to_cpu(pModal->antCtrlCommon)); /* Single chain for 4K EEPROM*/ ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal); @@ -858,6 +803,24 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal); regVal = REG_READ(ah, AR_PHY_CCK_DETECT); + + if (pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { + /* + * If diversity combining is enabled, + * set MAIN to LNA1 and ALT to LNA2 initially. + */ + regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL); + regVal &= (~(AR_PHY_9285_ANT_DIV_MAIN_LNACONF | + AR_PHY_9285_ANT_DIV_ALT_LNACONF)); + + regVal |= (ATH_ANT_DIV_COMB_LNA1 << + AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S); + regVal |= (ATH_ANT_DIV_COMB_LNA2 << + AR_PHY_9285_ANT_DIV_ALT_LNACONF_S); + regVal &= (~(AR_PHY_9285_FAST_DIV_BIAS)); + regVal |= (0 << AR_PHY_9285_FAST_DIV_BIAS_S); + REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal); + } } if (pModal->version >= 2) { @@ -895,6 +858,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, } } + ENABLE_REG_RMW_BUFFER(ah); if (AR_SREV_9271(ah)) { ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, @@ -999,18 +963,19 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, AR9285_AN_RF2G4_DB2_4_S, db2[4]); } + REG_RMW_BUFFER_FLUSH(ah); - + ENABLE_REG_RMW_BUFFER(ah); REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, pModal->switchSettling); REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); - REG_WRITE(ah, AR_PHY_RF_CTL4, - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | - SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | - SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + REG_RMW(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON), 0); REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); @@ -1023,22 +988,22 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { + if (ath9k_hw_4k_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_2) { REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart); REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn); } - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { + if (ath9k_hw_4k_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_3) { if (IS_CHAN_HT40(chan)) REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); } + REG_RMW_BUFFER_FLUSH(ah); + bb_desired_scale = (pModal->bb_scale_smrt_antenna & EEP_4K_BB_DESIRED_SCALE_MASK); if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) { @@ -1047,6 +1012,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25); pwrctrl = mask * bb_desired_scale; clr = mask * 0x1f; + ENABLE_REG_RMW_BUFFER(ah); REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr); REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr); REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr); @@ -1061,36 +1027,18 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, clr = mask * 0x1f; REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr); REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr); + REG_RMW_BUFFER_FLUSH(ah); } } static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) { -#define EEP_MAP4K_SPURCHAN \ - (ah->eeprom.map4k.modalHeader.spurChans[i].spurChan) - struct ath_common *common = ath9k_hw_common(ah); - - u16 spur_val = AR_NO_SPUR; - - ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); - - switch (ah->config.spurmode) { - case SPUR_DISABLE: - break; - case SPUR_ENABLE_IOCTL: - spur_val = ah->config.spurchans[i][is2GHz]; - ath_dbg(common, ANI, "Getting spur val from new loc. %d\n", - spur_val); - break; - case SPUR_ENABLE_EEPROM: - spur_val = EEP_MAP4K_SPURCHAN; - break; - } - - return spur_val; + return le16_to_cpu(ah->eeprom.map4k.modalHeader.spurChans[i].spurChan); +} -#undef EEP_MAP4K_SPURCHAN +static u8 ath9k_hw_4k_get_eepmisc(struct ath_hw *ah) +{ + return ah->eeprom.map4k.baseEepHeader.eepMisc; } const struct eeprom_ops eep_4k_ops = { @@ -1102,5 +1050,6 @@ const struct eeprom_ops eep_4k_ops = { .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, .set_board_values = ath9k_hw_4k_set_board_values, .set_txpower = ath9k_hw_4k_set_txpower, - .get_spur_channel = ath9k_hw_4k_get_spur_channel + .get_spur_channel = ath9k_hw_4k_get_spur_channel, + .get_eepmisc = ath9k_hw_4k_get_eepmisc }; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 3ae1f3df0637..c139ac49ccf6 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include "hw.h" #include "ar9002_phy.h" @@ -22,12 +22,17 @@ static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah) { - return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF; + u16 version = le16_to_cpu(ah->eeprom.map9287.baseEepHeader.version); + + return (version & AR5416_EEP_VER_MAJOR_MASK) >> + AR5416_EEP_VER_MAJOR_SHIFT; } static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah) { - return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF; + u16 version = le16_to_cpu(ah->eeprom.map9287.baseEepHeader.version); + + return version & AR5416_EEP_VER_MINOR_MASK; } static bool __ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) @@ -70,13 +75,13 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) return __ath9k_hw_ar9287_fill_eeprom(ah); } -#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS) +#ifdef CONFIG_ATH9K_COMMON_DEBUG static u32 ar9287_dump_modal_eeprom(char *buf, u32 len, u32 size, struct modal_eep_ar9287_header *modal_hdr) { - PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]); - PR_EEP("Chain1 Ant. Control", modal_hdr->antCtrlChain[1]); - PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon); + PR_EEP("Chain0 Ant. Control", le32_to_cpu(modal_hdr->antCtrlChain[0])); + PR_EEP("Chain1 Ant. Control", le32_to_cpu(modal_hdr->antCtrlChain[1])); + PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon)); PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]); PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]); PR_EEP("Switch Settle", modal_hdr->switchSettling); @@ -123,21 +128,22 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, { struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; + u32 binBuildNumber = le32_to_cpu(pBase->binBuildNumber); if (!dump_base_hdr) { - len += snprintf(buf + len, size - len, - "%20s :\n", "2GHz modal Header"); + len += scnprintf(buf + len, size - len, + "%20s :\n", "2GHz modal Header"); len = ar9287_dump_modal_eeprom(buf, len, size, &eep->modalHeader); goto out; } - PR_EEP("Major Version", pBase->version >> 12); - PR_EEP("Minor Version", pBase->version & 0xFFF); - PR_EEP("Checksum", pBase->checksum); - PR_EEP("Length", pBase->length); - PR_EEP("RegDomain1", pBase->regDmn[0]); - PR_EEP("RegDomain2", pBase->regDmn[1]); + PR_EEP("Major Version", ath9k_hw_ar9287_get_eeprom_ver(ah)); + PR_EEP("Minor Version", ath9k_hw_ar9287_get_eeprom_rev(ah)); + PR_EEP("Checksum", le16_to_cpu(pBase->checksum)); + PR_EEP("Length", le16_to_cpu(pBase->length)); + PR_EEP("RegDomain1", le16_to_cpu(pBase->regDmn[0])); + PR_EEP("RegDomain2", le16_to_cpu(pBase->regDmn[1])); PR_EEP("TX Mask", pBase->txMask); PR_EEP("RX Mask", pBase->rxMask); PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); @@ -150,15 +156,15 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, AR5416_OPFLAGS_N_5G_HT20)); PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT40)); - PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01)); - PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF); - PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF); - PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF); + PR_EEP("Big Endian", !!(pBase->eepMisc & AR5416_EEPMISC_BIG_ENDIAN)); + PR_EEP("Cal Bin Major Ver", (binBuildNumber >> 24) & 0xFF); + PR_EEP("Cal Bin Minor Ver", (binBuildNumber >> 16) & 0xFF); + PR_EEP("Cal Bin Build", (binBuildNumber >> 8) & 0xFF); PR_EEP("Power Table Offset", pBase->pwrTableOffset); PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl); - len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", - pBase->macAddr); + len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", + pBase->macAddr); out: if (len > size) @@ -177,118 +183,59 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah) { - u32 sum = 0, el, integer; - u16 temp, word, magic, magic2, *eepdata; - int i, addr; - bool need_swap = false; + u32 el; + int i, err; + bool need_swap; struct ar9287_eeprom *eep = &ah->eeprom.map9287; - struct ath_common *common = ath9k_hw_common(ah); - - if (!ath9k_hw_use_flash(ah)) { - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, - &magic)) { - ath_err(common, "Reading Magic # failed\n"); - return false; - } - - ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic); - - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - if (magic2 == AR5416_EEPROM_MAGIC) { - need_swap = true; - eepdata = (u16 *)(&ah->eeprom); - - for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } else { - ath_err(common, - "Invalid EEPROM Magic. Endianness mismatch.\n"); - return -EINVAL; - } - } - } - - ath_dbg(common, EEPROM, "need_swap = %s\n", - need_swap ? "True" : "False"); + err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_AR9287); + if (err) + return err; if (need_swap) - el = swab16(ah->eeprom.map9287.baseEepHeader.length); - else - el = ah->eeprom.map9287.baseEepHeader.length; - - if (el > sizeof(struct ar9287_eeprom)) - el = sizeof(struct ar9287_eeprom) / sizeof(u16); + el = swab16((__force u16)eep->baseEepHeader.length); else - el = el / sizeof(u16); + el = le16_to_cpu(eep->baseEepHeader.length); - eepdata = (u16 *)(&ah->eeprom); - - for (i = 0; i < el; i++) - sum ^= *eepdata++; + el = min(el / sizeof(u16), SIZE_EEPROM_AR9287); + if (!ath9k_hw_nvram_validate_checksum(ah, el)) + return -EINVAL; if (need_swap) { - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; - - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; - - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; - - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; - - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; - - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; - - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; - - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; - - integer = swab32(eep->modalHeader.antCtrlCommon); - eep->modalHeader.antCtrlCommon = integer; - - for (i = 0; i < AR9287_MAX_CHAINS; i++) { - integer = swab32(eep->modalHeader.antCtrlChain[i]); - eep->modalHeader.antCtrlChain[i] = integer; - } - - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - word = swab16(eep->modalHeader.spurChans[i].spurChan); - eep->modalHeader.spurChans[i].spurChan = word; - } + EEPROM_FIELD_SWAB16(eep->baseEepHeader.length); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.checksum); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.version); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[0]); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[1]); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.rfSilent); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.blueToothOptions); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.deviceCap); + EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlCommon); + + for (i = 0; i < AR9287_MAX_CHAINS; i++) + EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlChain[i]); + + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) + EEPROM_FIELD_SWAB16( + eep->modalHeader.spurChans[i].spurChan); } - if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER - || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); + if (!ath9k_hw_nvram_check_version(ah, AR9287_EEP_VER, + AR5416_EEP_NO_BACK_VER)) return -EINVAL; - } return 0; } +#undef SIZE_EEPROM_AR9287 + static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah, enum eeprom_param param) { struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &eep->modalHeader; struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; - u16 ver_minor; - - ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK; + u16 ver_minor = ath9k_hw_ar9287_get_eeprom_rev(ah); switch (param) { case EEP_NFTHRESH_2: @@ -300,15 +247,13 @@ static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah, case EEP_MAC_MSW: return get_unaligned_be16(pBase->macAddr + 4); case EEP_REG_0: - return pBase->regDmn[0]; + return le16_to_cpu(pBase->regDmn[0]); case EEP_OP_CAP: - return pBase->deviceCap; + return le16_to_cpu(pBase->deviceCap); case EEP_OP_MODE: return pBase->opCapFlags; case EEP_RF_SILENT: - return pBase->rfSilent; - case EEP_MINOR_REV: - return ver_minor; + return le16_to_cpu(pBase->rfSilent); case EEP_TX_MASK: return pBase->txMask; case EEP_RX_MASK: @@ -423,8 +368,7 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, xpdMask = pEepData->modalHeader.xpdGain; - if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= - AR9287_EEP_MINOR_VER_2) + if (ath9k_hw_ar9287_get_eeprom_rev(ah) >= AR9287_EEP_MINOR_VER_2) pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; else pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), @@ -628,8 +572,7 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, } for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = - (pCtlMode[ctlMode] == CTL_2GHT40) ? true : false; + bool isHt40CtlMode = pCtlMode[ctlMode] == CTL_2GHT40; if (isHt40CtlMode) freq = centers.synth_center; @@ -773,8 +716,7 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, memset(ratesArray, 0, sizeof(ratesArray)); - if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= - AR9287_EEP_MINOR_VER_2) + if (ath9k_hw_ar9287_get_eeprom_rev(ah) >= AR9287_EEP_MINOR_VER_2) ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; ath9k_hw_set_ar9287_power_per_rate_table(ah, chan, @@ -886,6 +828,21 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } + + /* TPC initializations */ + if (ah->tpc_enabled) { + int ht40_delta; + + ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0; + ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta); + /* Enable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, + MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE); + } else { + /* Disable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER); + } + REGWRITE_BUFFER_FLUSH(ah); } @@ -900,13 +857,13 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah, pModal = &eep->modalHeader; - REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); + REG_WRITE(ah, AR_PHY_SWITCH_COM, le32_to_cpu(pModal->antCtrlCommon)); for (i = 0; i < AR9287_MAX_CHAINS; i++) { regChainOffset = i * 0x1000; REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, - pModal->antCtrlChain[i]); + le32_to_cpu(pModal->antCtrlChain[i])); REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) @@ -1004,31 +961,14 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah, static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) { -#define EEP_MAP9287_SPURCHAN \ - (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan) + __le16 spur_ch = ah->eeprom.map9287.modalHeader.spurChans[i].spurChan; - struct ath_common *common = ath9k_hw_common(ah); - u16 spur_val = AR_NO_SPUR; - - ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); - - switch (ah->config.spurmode) { - case SPUR_DISABLE: - break; - case SPUR_ENABLE_IOCTL: - spur_val = ah->config.spurchans[i][is2GHz]; - ath_dbg(common, ANI, "Getting spur val from new loc. %d\n", - spur_val); - break; - case SPUR_ENABLE_EEPROM: - spur_val = EEP_MAP9287_SPURCHAN; - break; - } - - return spur_val; + return le16_to_cpu(spur_ch); +} -#undef EEP_MAP9287_SPURCHAN +static u8 ath9k_hw_ar9287_get_eepmisc(struct ath_hw *ah) +{ + return ah->eeprom.map9287.baseEepHeader.eepMisc; } const struct eeprom_ops eep_ar9287_ops = { @@ -1040,5 +980,6 @@ const struct eeprom_ops eep_ar9287_ops = { .get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev, .set_board_values = ath9k_hw_ar9287_set_board_values, .set_txpower = ath9k_hw_ar9287_set_txpower, - .get_spur_channel = ath9k_hw_ar9287_get_spur_channel + .get_spur_channel = ath9k_hw_ar9287_get_spur_channel, + .get_eepmisc = ath9k_hw_ar9287_get_eepmisc }; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 1c25368b3836..5ba467cb7425 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include "hw.h" #include "ar9002_phy.h" @@ -79,12 +79,17 @@ static void ath9k_olc_get_pdadcs(struct ath_hw *ah, static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah) { - return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF); + u16 version = le16_to_cpu(ah->eeprom.def.baseEepHeader.version); + + return (version & AR5416_EEP_VER_MAJOR_MASK) >> + AR5416_EEP_VER_MAJOR_SHIFT; } static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) { - return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF); + u16 version = le16_to_cpu(ah->eeprom.def.baseEepHeader.version); + + return version & AR5416_EEP_VER_MINOR_MASK; } #define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) @@ -126,16 +131,14 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) return __ath9k_hw_def_fill_eeprom(ah); } -#undef SIZE_EEPROM_DEF - -#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS) +#ifdef CONFIG_ATH9K_COMMON_DEBUG static u32 ath9k_def_dump_modal_eeprom(char *buf, u32 len, u32 size, struct modal_eep_header *modal_hdr) { - PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]); - PR_EEP("Chain1 Ant. Control", modal_hdr->antCtrlChain[1]); - PR_EEP("Chain2 Ant. Control", modal_hdr->antCtrlChain[2]); - PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon); + PR_EEP("Chain0 Ant. Control", le32_to_cpu(modal_hdr->antCtrlChain[0])); + PR_EEP("Chain1 Ant. Control", le32_to_cpu(modal_hdr->antCtrlChain[1])); + PR_EEP("Chain2 Ant. Control", le32_to_cpu(modal_hdr->antCtrlChain[2])); + PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon)); PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]); PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]); PR_EEP("Chain2 Ant. Gain", modal_hdr->antennaGainCh[2]); @@ -191,9 +194,9 @@ static u32 ath9k_def_dump_modal_eeprom(char *buf, u32 len, u32 size, PR_EEP("Chain1 OutputBias", modal_hdr->ob_ch1); PR_EEP("Chain1 DriverBias", modal_hdr->db_ch1); PR_EEP("LNA Control", modal_hdr->lna_ctl); - PR_EEP("XPA Bias Freq0", modal_hdr->xpaBiasLvlFreq[0]); - PR_EEP("XPA Bias Freq1", modal_hdr->xpaBiasLvlFreq[1]); - PR_EEP("XPA Bias Freq2", modal_hdr->xpaBiasLvlFreq[2]); + PR_EEP("XPA Bias Freq0", le16_to_cpu(modal_hdr->xpaBiasLvlFreq[0])); + PR_EEP("XPA Bias Freq1", le16_to_cpu(modal_hdr->xpaBiasLvlFreq[1])); + PR_EEP("XPA Bias Freq2", le16_to_cpu(modal_hdr->xpaBiasLvlFreq[2])); return len; } @@ -203,25 +206,26 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, { struct ar5416_eeprom_def *eep = &ah->eeprom.def; struct base_eep_header *pBase = &eep->baseEepHeader; + u32 binBuildNumber = le32_to_cpu(pBase->binBuildNumber); if (!dump_base_hdr) { - len += snprintf(buf + len, size - len, - "%20s :\n", "2GHz modal Header"); + len += scnprintf(buf + len, size - len, + "%20s :\n", "2GHz modal Header"); len = ath9k_def_dump_modal_eeprom(buf, len, size, &eep->modalHeader[0]); - len += snprintf(buf + len, size - len, - "%20s :\n", "5GHz modal Header"); + len += scnprintf(buf + len, size - len, + "%20s :\n", "5GHz modal Header"); len = ath9k_def_dump_modal_eeprom(buf, len, size, &eep->modalHeader[1]); goto out; } - PR_EEP("Major Version", pBase->version >> 12); - PR_EEP("Minor Version", pBase->version & 0xFFF); - PR_EEP("Checksum", pBase->checksum); - PR_EEP("Length", pBase->length); - PR_EEP("RegDomain1", pBase->regDmn[0]); - PR_EEP("RegDomain2", pBase->regDmn[1]); + PR_EEP("Major Version", ath9k_hw_def_get_eeprom_ver(ah)); + PR_EEP("Minor Version", ath9k_hw_def_get_eeprom_rev(ah)); + PR_EEP("Checksum", le16_to_cpu(pBase->checksum)); + PR_EEP("Length", le16_to_cpu(pBase->length)); + PR_EEP("RegDomain1", le16_to_cpu(pBase->regDmn[0])); + PR_EEP("RegDomain2", le16_to_cpu(pBase->regDmn[1])); PR_EEP("TX Mask", pBase->txMask); PR_EEP("RX Mask", pBase->rxMask); PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); @@ -234,14 +238,14 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, AR5416_OPFLAGS_N_5G_HT20)); PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT40)); - PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01)); - PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF); - PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF); - PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF); + PR_EEP("Big Endian", !!(pBase->eepMisc & AR5416_EEPMISC_BIG_ENDIAN)); + PR_EEP("Cal Bin Major Ver", (binBuildNumber >> 24) & 0xFF); + PR_EEP("Cal Bin Minor Ver", (binBuildNumber >> 16) & 0xFF); + PR_EEP("Cal Bin Build", (binBuildNumber >> 8) & 0xFF); PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl); - len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", - pBase->macAddr); + len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", + pBase->macAddr); out: if (len > size) @@ -257,126 +261,63 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, } #endif - static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) { struct ar5416_eeprom_def *eep = &ah->eeprom.def; struct ath_common *common = ath9k_hw_common(ah); - u16 *eepdata, temp, magic, magic2; - u32 sum = 0, el; - bool need_swap = false; - int i, addr, size; - - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { - ath_err(common, "Reading Magic # failed\n"); - return false; - } + u32 el; + bool need_swap; + int i, err; - if (!ath9k_hw_use_flash(ah)) { - ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic); - - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - size = sizeof(struct ar5416_eeprom_def); - need_swap = true; - eepdata = (u16 *) (&ah->eeprom); - - for (addr = 0; addr < size / sizeof(u16); addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } else { - ath_err(common, - "Invalid EEPROM Magic. Endianness mismatch.\n"); - return -EINVAL; - } - } - } - - ath_dbg(common, EEPROM, "need_swap = %s\n", - need_swap ? "True" : "False"); + err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_DEF); + if (err) + return err; if (need_swap) - el = swab16(ah->eeprom.def.baseEepHeader.length); - else - el = ah->eeprom.def.baseEepHeader.length; - - if (el > sizeof(struct ar5416_eeprom_def)) - el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); + el = swab16((__force u16)eep->baseEepHeader.length); else - el = el / sizeof(u16); + el = le16_to_cpu(eep->baseEepHeader.length); - eepdata = (u16 *)(&ah->eeprom); - - for (i = 0; i < el; i++) - sum ^= *eepdata++; + el = min(el / sizeof(u16), SIZE_EEPROM_DEF); + if (!ath9k_hw_nvram_validate_checksum(ah, el)) + return -EINVAL; if (need_swap) { - u32 integer, j; - u16 word; - - ath_dbg(common, EEPROM, - "EEPROM Endianness is not native.. Changing.\n"); - - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; - - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; + u32 j; - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; - - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; - - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; - - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; - - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; - - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; + EEPROM_FIELD_SWAB16(eep->baseEepHeader.length); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.checksum); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.version); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[0]); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[1]); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.rfSilent); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.blueToothOptions); + EEPROM_FIELD_SWAB16(eep->baseEepHeader.deviceCap); for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { struct modal_eep_header *pModal = &eep->modalHeader[j]; - integer = swab32(pModal->antCtrlCommon); - pModal->antCtrlCommon = integer; + EEPROM_FIELD_SWAB32(pModal->antCtrlCommon); - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - integer = swab32(pModal->antCtrlChain[i]); - pModal->antCtrlChain[i] = integer; - } - for (i = 0; i < 3; i++) { - word = swab16(pModal->xpaBiasLvlFreq[i]); - pModal->xpaBiasLvlFreq[i] = word; - } + for (i = 0; i < AR5416_MAX_CHAINS; i++) + EEPROM_FIELD_SWAB32(pModal->antCtrlChain[i]); - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - word = swab16(pModal->spurChans[i].spurChan); - pModal->spurChans[i].spurChan = word; - } + for (i = 0; i < 3; i++) + EEPROM_FIELD_SWAB16(pModal->xpaBiasLvlFreq[i]); + + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) + EEPROM_FIELD_SWAB16( + pModal->spurChans[i].spurChan); } } - if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || - ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { - ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ah->eep_ops->get_eeprom_ver(ah)); + if (!ath9k_hw_nvram_check_version(ah, AR5416_EEP_VER, + AR5416_EEP_NO_BACK_VER)) return -EINVAL; - } /* Enable fixup for AR_AN_TOP2 if necessary */ if ((ah->hw_version.devid == AR9280_DEVID_PCI) && - ((eep->baseEepHeader.version & 0xff) > 0x0a) && + ((le16_to_cpu(eep->baseEepHeader.version) & 0xff) > 0x0a) && (eep->baseEepHeader.pwdclkind == 0)) ah->need_an_top2_fixup = true; @@ -387,6 +328,8 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) return 0; } +#undef SIZE_EEPROM_DEF + static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, enum eeprom_param param) { @@ -407,13 +350,13 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, case EEP_MAC_MSW: return get_unaligned_be16(pBase->macAddr + 4); case EEP_REG_0: - return pBase->regDmn[0]; + return le16_to_cpu(pBase->regDmn[0]); case EEP_OP_CAP: - return pBase->deviceCap; + return le16_to_cpu(pBase->deviceCap); case EEP_OP_MODE: return pBase->opCapFlags; case EEP_RF_SILENT: - return pBase->rfSilent; + return le16_to_cpu(pBase->rfSilent); case EEP_OB_5: return pModal[0].ob; case EEP_DB_5: @@ -422,8 +365,6 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, return pModal[1].ob; case EEP_DB_2: return pModal[1].db; - case EEP_MINOR_REV: - return AR5416_VER_MASK; case EEP_TX_MASK: return pBase->txMask; case EEP_RX_MASK: @@ -435,33 +376,33 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, case EEP_TXGAIN_TYPE: return pBase->txGainType; case EEP_OL_PWRCTRL: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_19) return pBase->openLoopPwrCntl ? true : false; else return false; case EEP_RC_CHAIN_MASK: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_19) return pBase->rcChainMask; else return 0; case EEP_DAC_HPWR_5G: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) + if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_20) return pBase->dacHiPwrMode_5G; else return 0; case EEP_FRAC_N_5G: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22) + if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_22) return pBase->frac_n_5g; else return 0; case EEP_PWR_TABLE_OFFSET: - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_21) + if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_21) return pBase->pwr_table_offset; else return AR5416_PWR_TABLE_OFFSET_DB; case EEP_ANTENNA_GAIN_2G: band = 1; - /* fall through */ + fallthrough; case EEP_ANTENNA_GAIN_5G: return max_t(u8, max_t(u8, pModal[band].antennaGainCh[0], @@ -477,7 +418,8 @@ static void ath9k_hw_def_set_gain(struct ath_hw *ah, struct ar5416_eeprom_def *eep, u8 txRxAttenLocal, int regChainOffset, int i) { - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { + ENABLE_REG_RMW_BUFFER(ah); + if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_3) { txRxAttenLocal = pModal->txRxAttenCh[i]; if (AR_SREV_9280_20_OR_LATER(ah)) { @@ -494,16 +436,12 @@ static void ath9k_hw_def_set_gain(struct ath_hw *ah, AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[i]); } else { - REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) - | SM(pModal-> bswMargin[i], - AR_PHY_GAIN_2GHZ_BSW_MARGIN)); - REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) - | SM(pModal->bswAtten[i], - AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + REG_RMW(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + SM(pModal-> bswMargin[i], AR_PHY_GAIN_2GHZ_BSW_MARGIN), + AR_PHY_GAIN_2GHZ_BSW_MARGIN); + REG_RMW(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + SM(pModal->bswAtten[i], AR_PHY_GAIN_2GHZ_BSW_ATTEN), + AR_PHY_GAIN_2GHZ_BSW_ATTEN); } } @@ -515,17 +453,14 @@ static void ath9k_hw_def_set_gain(struct ath_hw *ah, AR_PHY_RXGAIN + regChainOffset, AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]); } else { - REG_WRITE(ah, - AR_PHY_RXGAIN + regChainOffset, - (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & - ~AR_PHY_RXGAIN_TXRX_ATTEN) - | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN)); - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | - SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); + REG_RMW(ah, AR_PHY_RXGAIN + regChainOffset, + SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN), + AR_PHY_RXGAIN_TXRX_ATTEN); + REG_RMW(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN), + AR_PHY_GAIN_2GHZ_RXTX_MARGIN); } + REG_RMW_BUFFER_FLUSH(ah); } static void ath9k_hw_def_set_board_values(struct ath_hw *ah, @@ -535,11 +470,13 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah, struct ar5416_eeprom_def *eep = &ah->eeprom.def; int i, regChainOffset; u8 txRxAttenLocal; + u32 antCtrlCommon; pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; + antCtrlCommon = le32_to_cpu(pModal->antCtrlCommon); - REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon & 0xffff); + REG_WRITE(ah, AR_PHY_SWITCH_COM, antCtrlCommon & 0xffff); for (i = 0; i < AR5416_MAX_CHAINS; i++) { if (AR_SREV_9280(ah)) { @@ -553,7 +490,7 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah, regChainOffset = i * 0x1000; REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, - pModal->antCtrlChain[i]); + le32_to_cpu(pModal->antCtrlChain[i])); REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & @@ -653,7 +590,7 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah, pModal->thresh62); } - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) { + if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_2) { REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart); @@ -661,7 +598,7 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah, pModal->txFrameToPaOn); } - if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { + if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_3) { if (IS_CHAN_HT40(chan)) REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, @@ -669,13 +606,14 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah, } if (AR_SREV_9280_20_OR_LATER(ah) && - AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) + ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_19) REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, pModal->miscBits); - if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { + if (AR_SREV_9280_20(ah) && + ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_20) { if (IS_CHAN_2GHZ(chan)) REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, eep->baseEepHeader.dacLpMode); @@ -699,7 +637,7 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah, static void ath9k_hw_def_set_addac(struct ath_hw *ah, struct ath9k_channel *chan) { -#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) +#define XPA_LVL_FREQ(cnt) (le16_to_cpu(pModal->xpaBiasLvlFreq[cnt])) struct modal_eep_header *pModal; struct ar5416_eeprom_def *eep = &ah->eeprom.def; u8 biaslevel; @@ -846,8 +784,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, pwr_table_offset = ah->eep_ops->get_eeprom(ah, EEP_PWR_TABLE_OFFSET); - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { + if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_2) { pdGainOverlap_t2 = pEepData->modalHeader[modalIdx].pdGainOverlap; } else { @@ -863,7 +800,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, numPiers = AR5416_NUM_5G_CAL_PIERS; } - if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) { + if (OLC_FOR_AR9280_20_LATER(ah) && IS_CHAN_2GHZ(chan)) { pRawDataset = pEepData->calPierData2G[0]; ah->initPDADC = ((struct calDataPerFreqOpLoop *) pRawDataset)->vpdPdg[0][0]; @@ -904,7 +841,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, pRawDataset = pEepData->calPierData5G[i]; - if (OLC_FOR_AR9280_20_LATER) { + if (OLC_FOR_AR9280_20_LATER(ah)) { u8 pcdacIdx; u8 txPower; @@ -932,7 +869,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, ENABLE_REGWRITE_BUFFER(ah); - if (OLC_FOR_AR9280_20_LATER) { + if (OLC_FOR_AR9280_20_LATER(ah)) { REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, SM(0x6, @@ -1219,10 +1156,8 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, memset(ratesArray, 0, sizeof(ratesArray)); - if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { + if (ath9k_hw_def_get_eeprom_rev(ah) >= AR5416_EEP_MINOR_VER_2) ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - } ath9k_hw_set_def_power_per_rate_table(ah, chan, &ratesArray[0], cfgCtl, @@ -1268,7 +1203,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rate24mb], 0)); if (IS_CHAN_2GHZ(chan)) { - if (OLC_FOR_AR9280_20_LATER) { + if (OLC_FOR_AR9280_20_LATER(ah)) { cck_ofdm_delta = 2; REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24) @@ -1324,7 +1259,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, ht40PowerIncForPdadc, 8) | ATH9K_POW_SM(ratesArray[rateHt40_4] + ht40PowerIncForPdadc, 0)); - if (OLC_FOR_AR9280_20_LATER) { + if (OLC_FOR_AR9280_20_LATER(ah)) { REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16) @@ -1343,36 +1278,33 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + /* TPC initializations */ + if (ah->tpc_enabled) { + int ht40_delta; + + ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0; + ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta); + /* Enable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, + MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE); + } else { + /* Disable TPC */ + REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER); + } + REGWRITE_BUFFER_FLUSH(ah); } static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz) { -#define EEP_DEF_SPURCHAN \ - (ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) - struct ath_common *common = ath9k_hw_common(ah); - - u16 spur_val = AR_NO_SPUR; - - ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n", - i, is2GHz, ah->config.spurchans[i][is2GHz]); - - switch (ah->config.spurmode) { - case SPUR_DISABLE: - break; - case SPUR_ENABLE_IOCTL: - spur_val = ah->config.spurchans[i][is2GHz]; - ath_dbg(common, ANI, "Getting spur val from new loc. %d\n", - spur_val); - break; - case SPUR_ENABLE_EEPROM: - spur_val = EEP_DEF_SPURCHAN; - break; - } + __le16 spch = ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan; - return spur_val; + return le16_to_cpu(spch); +} -#undef EEP_DEF_SPURCHAN +static u8 ath9k_hw_def_get_eepmisc(struct ath_hw *ah) +{ + return ah->eeprom.def.baseEepHeader.eepMisc; } const struct eeprom_ops eep_def_ops = { @@ -1385,5 +1317,6 @@ const struct eeprom_ops eep_def_ops = { .set_board_values = ath9k_hw_def_set_board_values, .set_addac = ath9k_hw_def_set_addac, .set_txpower = ath9k_hw_def_set_txpower, - .get_spur_channel = ath9k_hw_def_get_spur_channel + .get_spur_channel = ath9k_hw_def_get_spur_channel, + .get_eepmisc = ath9k_hw_def_get_eepmisc }; diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 4b412aaf4f36..2dbc7efdd637 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -21,11 +21,43 @@ /********************************/ #ifdef CONFIG_MAC80211_LEDS + +static void ath_fill_led_pin(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + /* Set default led pin if invalid */ + if (ah->led_pin < 0) { + if (AR_SREV_9287(ah)) + ah->led_pin = ATH_LED_PIN_9287; + else if (AR_SREV_9485(ah)) + ah->led_pin = ATH_LED_PIN_9485; + else if (AR_SREV_9300(ah)) + ah->led_pin = ATH_LED_PIN_9300; + else if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) + ah->led_pin = ATH_LED_PIN_9462; + else + ah->led_pin = ATH_LED_PIN_DEF; + } + + /* Configure gpio for output */ + ath9k_hw_gpio_request_out(ah, ah->led_pin, "ath9k-led", + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + + /* LED off, active low */ + ath9k_hw_set_gpio(ah, ah->led_pin, ah->config.led_active_high ? 0 : 1); +} + static void ath_led_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) { struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev); - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (brightness == LED_OFF)); + u32 val = (brightness == LED_OFF); + + if (sc->sc_ah->config.led_active_high) + val = !val; + + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, val); } void ath_deinit_leds(struct ath_softc *sc) @@ -35,6 +67,8 @@ void ath_deinit_leds(struct ath_softc *sc) ath_led_brightness(&sc->led_cdev, LED_OFF); led_classdev_unregister(&sc->led_cdev); + + ath9k_hw_gpio_free(sc->sc_ah, sc->sc_ah->led_pin); } void ath_init_leds(struct ath_softc *sc) @@ -44,7 +78,9 @@ void ath_init_leds(struct ath_softc *sc) if (AR_SREV_9100(sc->sc_ah)) return; - if (!led_blink) + ath_fill_led_pin(sc); + + if (!ath9k_led_blink) sc->led_cdev.default_trigger = ieee80211_get_radio_led_name(sc->hw); @@ -59,31 +95,6 @@ void ath_init_leds(struct ath_softc *sc) sc->led_registered = true; } - -void ath_fill_led_pin(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - if (AR_SREV_9100(ah) || (ah->led_pin >= 0)) - return; - - if (AR_SREV_9287(ah)) - ah->led_pin = ATH_LED_PIN_9287; - else if (AR_SREV_9485(sc->sc_ah)) - ah->led_pin = ATH_LED_PIN_9485; - else if (AR_SREV_9300(sc->sc_ah)) - ah->led_pin = ATH_LED_PIN_9300; - else if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah)) - ah->led_pin = ATH_LED_PIN_9462; - else - ah->led_pin = ATH_LED_PIN_DEF; - - /* Configure gpio 1 for output */ - ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - - /* LED off, active low */ - ath9k_hw_set_gpio(ah, ah->led_pin, 1); -} #endif /*******************/ @@ -157,36 +168,6 @@ static void ath_detect_bt_priority(struct ath_softc *sc) } } -static void ath9k_gen_timer_start(struct ath_hw *ah, - struct ath_gen_timer *timer, - u32 trig_timeout, - u32 timer_period) -{ - ath9k_hw_gen_timer_start(ah, timer, trig_timeout, timer_period); - - if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { - ath9k_hw_disable_interrupts(ah); - ah->imask |= ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah); - ath9k_hw_enable_interrupts(ah); - } -} - -static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) -{ - struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; - - ath9k_hw_gen_timer_stop(ah, timer); - - /* if no timer is enabled, turn off interrupt mask */ - if (timer_table->timer_mask.val == 0) { - ath9k_hw_disable_interrupts(ah); - ah->imask &= ~ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah); - ath9k_hw_enable_interrupts(ah); - } -} - static void ath_mci_ftp_adjust(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; @@ -210,9 +191,9 @@ static void ath_mci_ftp_adjust(struct ath_softc *sc) * 45ms, bt traffic will be given priority during 55% of this * period while wlan gets remaining 45% */ -static void ath_btcoex_period_timer(unsigned long data) +static void ath_btcoex_period_timer(struct timer_list *t) { - struct ath_softc *sc = (struct ath_softc *) data; + struct ath_softc *sc = timer_container_of(sc, t, btcoex.period_timer); struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; enum ath_stomp_type stomp_type; @@ -227,17 +208,16 @@ static void ath_btcoex_period_timer(unsigned long data) } spin_unlock_irqrestore(&sc->sc_pm_lock, flags); - ath9k_mci_update_rssi(sc); - ath9k_ps_wakeup(sc); + spin_lock_bh(&btcoex->btcoex_lock); - if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) - ath_detect_bt_priority(sc); - - if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) + if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) { + ath9k_mci_update_rssi(sc); ath_mci_ftp_adjust(sc); + } - spin_lock_bh(&btcoex->btcoex_lock); + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) + ath_detect_bt_priority(sc); stomp_type = btcoex->bt_stomp_type; timer_period = btcoex->btcoex_no_stomp; @@ -257,19 +237,9 @@ static void ath_btcoex_period_timer(unsigned long data) spin_unlock_bh(&btcoex->btcoex_lock); - /* - * btcoex_period is in msec while (btocex/btscan_)no_stomp are in usec, - * ensure that we properly convert btcoex_period to usec - * for any comparision with (btcoex/btscan_)no_stomp. - */ - if (btcoex->btcoex_period * 1000 != btcoex->btcoex_no_stomp) { - if (btcoex->hw_timer_enabled) - ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); - - ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period, - timer_period * 10); - btcoex->hw_timer_enabled = true; - } + if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) + mod_timer(&btcoex->no_stomp_timer, + jiffies + msecs_to_jiffies(timer_period)); ath9k_ps_restore(sc); @@ -282,14 +252,12 @@ skip_hw_wakeup: * Generic tsf based hw timer which configures weight * registers to time slice between wlan and bt traffic */ -static void ath_btcoex_no_stomp_timer(void *arg) +static void ath_btcoex_no_stomp_timer(struct timer_list *t) { - struct ath_softc *sc = (struct ath_softc *)arg; + struct ath_softc *sc = timer_container_of(sc, t, + btcoex.no_stomp_timer); struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_common *common = ath9k_hw_common(ah); - - ath_dbg(common, BTCOEX, "no stomp timer running\n"); ath9k_ps_wakeup(sc); spin_lock_bh(&btcoex->btcoex_lock); @@ -306,30 +274,21 @@ static void ath_btcoex_no_stomp_timer(void *arg) ath9k_ps_restore(sc); } -static int ath_init_btcoex_timer(struct ath_softc *sc) +static void ath_init_btcoex_timer(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD; - btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * 1000 * + btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * btcoex->btcoex_period / 100; - btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * 1000 * + btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * btcoex->btcoex_period / 100; + btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, - (unsigned long) sc); + timer_setup(&btcoex->period_timer, ath_btcoex_period_timer, 0); + timer_setup(&btcoex->no_stomp_timer, ath_btcoex_no_stomp_timer, 0); spin_lock_init(&btcoex->btcoex_lock); - - btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah, - ath_btcoex_no_stomp_timer, - ath_btcoex_no_stomp_timer, - (void *) sc, AR_FIRST_NDP_TIMER); - - if (!btcoex->no_stomp_timer) - return -ENOMEM; - - return 0; } /* @@ -340,13 +299,14 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc) struct ath_btcoex *btcoex = &sc->btcoex; struct ath_hw *ah = sc->sc_ah; + if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_3WIRE && + ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_MCI) + return; + ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n"); /* make sure duty cycle timer is also stopped when resuming */ - if (btcoex->hw_timer_enabled) { - ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); - btcoex->hw_timer_enabled = false; - } + timer_delete_sync(&btcoex->no_stomp_timer); btcoex->bt_priority_cnt = 0; btcoex->bt_priority_time = jiffies; @@ -356,7 +316,6 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc) mod_timer(&btcoex->period_timer, jiffies); } - /* * Pause btcoex timer and bt duty cycle timer */ @@ -365,22 +324,21 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc) struct ath_btcoex *btcoex = &sc->btcoex; struct ath_hw *ah = sc->sc_ah; - del_timer_sync(&btcoex->period_timer); + if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_3WIRE && + ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_MCI) + return; - if (btcoex->hw_timer_enabled) { - ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); - btcoex->hw_timer_enabled = false; - } + ath_dbg(ath9k_hw_common(ah), BTCOEX, "Stopping btcoex timers\n"); + + timer_delete_sync(&btcoex->period_timer); + timer_delete_sync(&btcoex->no_stomp_timer); } void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; - if (btcoex->hw_timer_enabled) { - ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); - btcoex->hw_timer_enabled = false; - } + timer_delete_sync(&btcoex->no_stomp_timer); } u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) @@ -400,12 +358,6 @@ u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status) { - struct ath_hw *ah = sc->sc_ah; - - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) - if (status & ATH9K_INT_GENTIMER) - ath_gen_timer_isr(sc->sc_ah); - if (status & ATH9K_INT_MCI) ath_mci_intr(sc); } @@ -414,45 +366,48 @@ void ath9k_start_btcoex(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) && - !ah->btcoex_hw.enabled) { - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT, 0); - else - ath9k_hw_btcoex_set_weight(ah, 0, 0, - ATH_BTCOEX_STOMP_NONE); - ath9k_hw_btcoex_enable(ah); + if (ah->btcoex_hw.enabled || + ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) + return; - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) - ath9k_btcoex_timer_resume(sc); - } + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT, 0); + else + ath9k_hw_btcoex_set_weight(ah, 0, 0, + ATH_BTCOEX_STOMP_NONE); + ath9k_hw_btcoex_enable(ah); + ath9k_btcoex_timer_resume(sc); } void ath9k_stop_btcoex(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - if (ah->btcoex_hw.enabled && - ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { - if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) - ath9k_btcoex_timer_pause(sc); - ath9k_hw_btcoex_disable(ah); - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) - ath_mci_flush_profile(&sc->btcoex.mci); - } + if (!ah->btcoex_hw.enabled || + ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE) + return; + + ath9k_btcoex_timer_pause(sc); + ath9k_hw_btcoex_disable(ah); + + if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) + ath_mci_flush_profile(&sc->btcoex.mci); } void ath9k_deinit_btcoex(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - if ((sc->btcoex.no_stomp_timer) && - ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE) - ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); - if (ath9k_hw_mci_is_enabled(ah)) ath_mci_cleanup(sc); + else { + enum ath_btcoex_scheme scheme = ath9k_hw_get_btcoex_scheme(ah); + + if (scheme == ATH_BTCOEX_CFG_2WIRE || + scheme == ATH_BTCOEX_CFG_3WIRE) + ath9k_hw_btcoex_deinit(sc->sc_ah); + } } int ath9k_init_btcoex(struct ath_softc *sc) @@ -471,22 +426,20 @@ int ath9k_init_btcoex(struct ath_softc *sc) break; case ATH_BTCOEX_CFG_3WIRE: ath9k_hw_btcoex_init_3wire(sc->sc_ah); - r = ath_init_btcoex_timer(sc); - if (r) - return -1; + ath_init_btcoex_timer(sc); txq = sc->tx.txq_map[IEEE80211_AC_BE]; ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); - sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - if (ath9k_hw_mci_is_enabled(ah)) { - sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; - INIT_LIST_HEAD(&sc->btcoex.mci.info); + break; + case ATH_BTCOEX_CFG_MCI: + ath_init_btcoex_timer(sc); - r = ath_mci_setup(sc); - if (r) - return r; + sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; + INIT_LIST_HEAD(&sc->btcoex.mci.info); + ath9k_hw_btcoex_init_mci(ah); - ath9k_hw_btcoex_init_mci(ah); - } + r = ath_mci_setup(sc); + if (r) + return r; break; default: @@ -522,22 +475,22 @@ static int ath9k_dump_mci_btcoex(struct ath_softc *sc, u8 *buf, u32 size) ATH_DUMP_BTCOEX("Concurrent Tx", btcoex_hw->mci.concur_tx); ATH_DUMP_BTCOEX("Concurrent RSSI cnt", btcoex->rssi_count); - len += snprintf(buf + len, size - len, "BT Weights: "); + len += scnprintf(buf + len, size - len, "BT Weights: "); for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) - len += snprintf(buf + len, size - len, "%08x ", - btcoex_hw->bt_weight[i]); - len += snprintf(buf + len, size - len, "\n"); - len += snprintf(buf + len, size - len, "WLAN Weights: "); + len += scnprintf(buf + len, size - len, "%08x ", + btcoex_hw->bt_weight[i]); + len += scnprintf(buf + len, size - len, "\n"); + len += scnprintf(buf + len, size - len, "WLAN Weights: "); for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) - len += snprintf(buf + len, size - len, "%08x ", - btcoex_hw->wlan_weight[i]); - len += snprintf(buf + len, size - len, "\n"); - len += snprintf(buf + len, size - len, "Tx Priorities: "); + len += scnprintf(buf + len, size - len, "%08x ", + btcoex_hw->wlan_weight[i]); + len += scnprintf(buf + len, size - len, "\n"); + len += scnprintf(buf + len, size - len, "Tx Priorities: "); for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++) - len += snprintf(buf + len, size - len, "%08x ", + len += scnprintf(buf + len, size - len, "%08x ", btcoex_hw->tx_prio[i]); - len += snprintf(buf + len, size - len, "\n"); + len += scnprintf(buf + len, size - len, "\n"); return len; } diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 9e582e14da74..fe9abe8cd268 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -14,20 +14,17 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include "htc.h" -/* identify firmware images */ -#define FIRMWARE_AR7010_1_1 "htc_7010.fw" -#define FIRMWARE_AR9271 "htc_9271.fw" +MODULE_FIRMWARE(HTC_7010_MODULE_FW); +MODULE_FIRMWARE(HTC_9271_MODULE_FW); -MODULE_FIRMWARE(FIRMWARE_AR7010_1_1); -MODULE_FIRMWARE(FIRMWARE_AR9271); - -static struct usb_device_id ath9k_hif_usb_ids[] = { +static const struct usb_device_id ath9k_hif_usb_ids[] = { { USB_DEVICE(0x0cf3, 0x9271) }, /* Atheros */ { USB_DEVICE(0x0cf3, 0x1006) }, /* Atheros */ { USB_DEVICE(0x0846, 0x9030) }, /* Netgear N150 */ + { USB_DEVICE(0x07b8, 0x9271) }, /* Altai WA1011N-GU */ { USB_DEVICE(0x07D1, 0x3A10) }, /* Dlink Wireless 150 */ { USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */ { USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */ @@ -40,11 +37,11 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { { USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */ { USB_DEVICE(0x0cf3, 0xb002) }, /* Ubiquiti WifiStation */ { USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */ + { USB_DEVICE(0x0471, 0x209e) }, /* Philips (or NXP) PTA01 */ + { USB_DEVICE(0x1eda, 0x2315) }, /* AirTies */ { USB_DEVICE(0x0cf3, 0x7015), .driver_info = AR9287_USB }, /* Atheros */ - { USB_DEVICE(0x1668, 0x1200), - .driver_info = AR9287_USB }, /* Verizon */ { USB_DEVICE(0x0cf3, 0x7010), .driver_info = AR9280_USB }, /* Atheros */ @@ -54,8 +51,12 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { .driver_info = AR9280_USB }, /* SMC Networks */ { USB_DEVICE(0x0411, 0x017f), .driver_info = AR9280_USB }, /* Sony UWA-BR100 */ + { USB_DEVICE(0x0411, 0x0197), + .driver_info = AR9280_USB }, /* Buffalo WLI-UV-AG300P */ { USB_DEVICE(0x04da, 0x3904), .driver_info = AR9280_USB }, + { USB_DEVICE(0x0930, 0x0a08), + .driver_info = AR9280_USB }, /* Toshiba WLM-20U2 and GN-1080 */ { USB_DEVICE(0x0cf3, 0x20ff), .driver_info = STORAGE_DEVICE }, @@ -69,7 +70,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev); static void hif_usb_regout_cb(struct urb *urb) { - struct cmd_buf *cmd = (struct cmd_buf *)urb->context; + struct cmd_buf *cmd = urb->context; switch (urb->status) { case 0: @@ -115,10 +116,10 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev, cmd->skb = skb; cmd->hif_dev = hif_dev; - usb_fill_bulk_urb(urb, hif_dev->udev, - usb_sndbulkpipe(hif_dev->udev, USB_REG_OUT_PIPE), + usb_fill_int_urb(urb, hif_dev->udev, + usb_sndintpipe(hif_dev->udev, USB_REG_OUT_PIPE), skb->data, skb->len, - hif_usb_regout_cb, cmd); + hif_usb_regout_cb, cmd, 1); usb_anchor_urb(urb, &hif_dev->regout_submitted); ret = usb_submit_urb(urb, GFP_KERNEL); @@ -133,8 +134,9 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev, static void hif_usb_mgmt_cb(struct urb *urb) { - struct cmd_buf *cmd = (struct cmd_buf *)urb->context; + struct cmd_buf *cmd = urb->context; struct hif_device_usb *hif_dev; + unsigned long flags; bool txok = true; if (!cmd || !cmd->skb || !cmd->hif_dev) @@ -155,14 +157,14 @@ static void hif_usb_mgmt_cb(struct urb *urb) * If the URBs are being flushed, no need to complete * this packet. */ - spin_lock(&hif_dev->tx.tx_lock); + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) { - spin_unlock(&hif_dev->tx.tx_lock); + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); dev_kfree_skb_any(cmd->skb); kfree(cmd); return; } - spin_unlock(&hif_dev->tx.tx_lock); + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); break; default: @@ -197,7 +199,7 @@ static int hif_usb_send_mgmt(struct hif_device_usb *hif_dev, cmd->skb = skb; cmd->hif_dev = hif_dev; - hdr = (__le16 *) skb_push(skb, 4); + hdr = skb_push(skb, 4); *hdr++ = cpu_to_le16(skb->len - 4); *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG); @@ -240,17 +242,17 @@ static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev, ath9k_htc_txcompletion_cb(hif_dev->htc_handle, skb, txok); if (txok) { - TX_STAT_INC(skb_success); - TX_STAT_ADD(skb_success_bytes, ln); + TX_STAT_INC(hif_dev, skb_success); + TX_STAT_ADD(hif_dev, skb_success_bytes, ln); } else - TX_STAT_INC(skb_failed); + TX_STAT_INC(hif_dev, skb_failed); } } static void hif_usb_tx_cb(struct urb *urb) { - struct tx_buf *tx_buf = (struct tx_buf *) urb->context; + struct tx_buf *tx_buf = urb->context; struct hif_device_usb *hif_dev; bool txok = true; @@ -298,7 +300,7 @@ static void hif_usb_tx_cb(struct urb *urb) hif_dev->tx.tx_buf_cnt++; if (!(hif_dev->tx.flags & HIF_USB_TX_STOP)) __hif_usb_tx(hif_dev); /* Check for pending SKBs */ - TX_STAT_INC(buf_completed); + TX_STAT_INC(hif_dev, buf_completed); spin_unlock(&hif_dev->tx.tx_lock); } @@ -349,7 +351,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev) tx_buf->len += tx_buf->offset; __skb_queue_tail(&tx_buf->skb_queue, nskb); - TX_STAT_INC(skb_queued); + TX_STAT_INC(hif_dev, skb_queued); } usb_fill_bulk_urb(tx_buf->urb, hif_dev->udev, @@ -364,11 +366,10 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev) __skb_queue_head_init(&tx_buf->skb_queue); list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf); hif_dev->tx.tx_buf_cnt++; + } else { + TX_STAT_INC(hif_dev, buf_queued); } - if (!ret) - TX_STAT_INC(buf_queued); - return ret; } @@ -422,7 +423,7 @@ static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb) static void hif_usb_start(void *hif_handle) { - struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; + struct hif_device_usb *hif_dev = hif_handle; unsigned long flags; hif_dev->flags |= HIF_USB_START; @@ -434,7 +435,7 @@ static void hif_usb_start(void *hif_handle) static void hif_usb_stop(void *hif_handle) { - struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; + struct hif_device_usb *hif_dev = hif_handle; struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; unsigned long flags; @@ -445,17 +446,26 @@ static void hif_usb_stop(void *hif_handle) spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); /* The pending URBs have to be canceled. */ + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); list_for_each_entry_safe(tx_buf, tx_buf_tmp, &hif_dev->tx.tx_pending, list) { + usb_get_urb(tx_buf->urb); + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); usb_kill_urb(tx_buf->urb); + list_del(&tx_buf->list); + usb_free_urb(tx_buf->urb); + kfree(tx_buf->buf); + kfree(tx_buf); + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); } + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); usb_kill_anchored_urbs(&hif_dev->mgmt_submitted); } static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb) { - struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; + struct hif_device_usb *hif_dev = hif_handle; int ret = 0; switch (pipe_id) { @@ -490,7 +500,7 @@ static inline bool check_index(struct sk_buff *skb, u8 idx) static void hif_usb_sta_drain(void *hif_handle, u8 idx) { - struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; + struct hif_device_usb *hif_dev = hif_handle; struct sk_buff *skb, *tmp; unsigned long flags; @@ -502,7 +512,7 @@ static void hif_usb_sta_drain(void *hif_handle, u8 idx) ath9k_htc_txcompletion_cb(hif_dev->htc_handle, skb, false); hif_dev->tx.tx_skb_cnt--; - TX_STAT_INC(skb_failed); + TX_STAT_INC(hif_dev, skb_failed); } } @@ -522,11 +532,29 @@ static struct ath9k_htc_hif hif_usb = { .send = hif_usb_send, }; +/* Need to free remain_skb allocated in ath9k_hif_usb_rx_stream + * in case ath9k_hif_usb_rx_stream wasn't called next time to + * process the buffer and subsequently free it. + */ +static void ath9k_hif_usb_free_rx_remain_skb(struct hif_device_usb *hif_dev) +{ + unsigned long flags; + + spin_lock_irqsave(&hif_dev->rx_lock, flags); + if (hif_dev->remain_skb) { + dev_kfree_skb_any(hif_dev->remain_skb); + hif_dev->remain_skb = NULL; + hif_dev->rx_remain_len = 0; + RX_STAT_INC(hif_dev, skb_dropped); + } + spin_unlock_irqrestore(&hif_dev->rx_lock, flags); +} + static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, struct sk_buff *skb) { struct sk_buff *nskb, *skb_pool[MAX_PKT_NUM_IN_TRANSFER]; - int index = 0, i = 0, len = skb->len; + int index = 0, i, len = skb->len; int rx_remain_len, rx_pkt_len; u16 pool_index = 0; u8 *ptr; @@ -549,11 +577,11 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, memcpy(ptr, skb->data, rx_remain_len); rx_pkt_len += rx_remain_len; - hif_dev->rx_remain_len = 0; skb_put(remain_skb, rx_pkt_len); skb_pool[pool_index++] = remain_skb; - + hif_dev->remain_skb = NULL; + hif_dev->rx_remain_len = 0; } else { index = rx_remain_len; } @@ -572,9 +600,21 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, pkt_len = get_unaligned_le16(ptr + index); pkt_tag = get_unaligned_le16(ptr + index + 2); + /* It is supposed that if we have an invalid pkt_tag or + * pkt_len then the whole input SKB is considered invalid + * and dropped; the associated packets already in skb_pool + * are dropped, too. + */ if (pkt_tag != ATH_USB_RX_STREAM_MODE_TAG) { - RX_STAT_INC(skb_dropped); - return; + RX_STAT_INC(hif_dev, skb_dropped); + goto invalid_pkt; + } + + if (pkt_len > 2 * MAX_RX_BUF_SIZE) { + dev_err(&hif_dev->udev->dev, + "ath9k_htc: invalid pkt_len (%x)\n", pkt_len); + RX_STAT_INC(hif_dev, skb_dropped); + goto invalid_pkt; } pad_len = 4 - (pkt_len & 0x3); @@ -586,11 +626,6 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, if (index > MAX_RX_BUF_SIZE) { spin_lock(&hif_dev->rx_lock); - hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE; - hif_dev->rx_transfer_len = - MAX_RX_BUF_SIZE - chk_idx - 4; - hif_dev->rx_pad_len = pad_len; - nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC); if (!nskb) { dev_err(&hif_dev->udev->dev, @@ -598,8 +633,14 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, spin_unlock(&hif_dev->rx_lock); goto err; } + + hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE; + hif_dev->rx_transfer_len = + MAX_RX_BUF_SIZE - chk_idx - 4; + hif_dev->rx_pad_len = pad_len; + skb_reserve(nskb, 32); - RX_STAT_INC(skb_allocated); + RX_STAT_INC(hif_dev, skb_allocated); memcpy(nskb->data, &(skb->data[chk_idx+4]), hif_dev->rx_transfer_len); @@ -608,6 +649,11 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, hif_dev->remain_skb = nskb; spin_unlock(&hif_dev->rx_lock); } else { + if (pool_index == MAX_PKT_NUM_IN_TRANSFER) { + dev_err(&hif_dev->udev->dev, + "ath9k_htc: over RX MAX_PKT_NUM\n"); + goto err; + } nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC); if (!nskb) { dev_err(&hif_dev->udev->dev, @@ -615,7 +661,7 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, goto err; } skb_reserve(nskb, 32); - RX_STAT_INC(skb_allocated); + RX_STAT_INC(hif_dev, skb_allocated); memcpy(nskb->data, &(skb->data[chk_idx+4]), pkt_len); skb_put(nskb, pkt_len); @@ -625,18 +671,25 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, err: for (i = 0; i < pool_index; i++) { - RX_STAT_ADD(skb_completed_bytes, skb_pool[i]->len); + RX_STAT_ADD(hif_dev, skb_completed_bytes, skb_pool[i]->len); ath9k_htc_rx_msg(hif_dev->htc_handle, skb_pool[i], skb_pool[i]->len, USB_WLAN_RX_PIPE); - RX_STAT_INC(skb_completed); + RX_STAT_INC(hif_dev, skb_completed); + } + return; +invalid_pkt: + for (i = 0; i < pool_index; i++) { + dev_kfree_skb_any(skb_pool[i]); + RX_STAT_INC(hif_dev, skb_dropped); } + return; } static void ath9k_hif_usb_rx_cb(struct urb *urb) { - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct hif_device_usb *hif_dev = - usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); + struct rx_buf *rx_buf = urb->context; + struct hif_device_usb *hif_dev = rx_buf->hif_dev; + struct sk_buff *skb = rx_buf->skb; int ret; if (!skb) @@ -663,8 +716,7 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) } resubmit: - skb_reset_tail_pointer(skb); - skb_trim(skb, 0); + __skb_set_length(skb, 0); usb_anchor_urb(urb, &hif_dev->rx_submitted); ret = usb_submit_urb(urb, GFP_ATOMIC); @@ -676,21 +728,21 @@ resubmit: return; free: kfree_skb(skb); + kfree(rx_buf); } static void ath9k_hif_usb_reg_in_cb(struct urb *urb) { - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct sk_buff *nskb; - struct hif_device_usb *hif_dev = - usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); + struct rx_buf *rx_buf = urb->context; + struct hif_device_usb *hif_dev = rx_buf->hif_dev; + struct sk_buff *skb = rx_buf->skb; int ret; if (!skb) return; if (!hif_dev) - goto free; + goto free_skb; switch (urb->status) { case 0: @@ -699,10 +751,9 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb) case -ECONNRESET: case -ENODEV: case -ESHUTDOWN: - goto free; + goto free_skb; default: - skb_reset_tail_pointer(skb); - skb_trim(skb, 0); + __skb_set_length(skb, 0); goto resubmit; } @@ -710,24 +761,28 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb) if (likely(urb->actual_length != 0)) { skb_put(skb, urb->actual_length); - /* Process the command first */ + /* + * Process the command first. + * skb is either freed here or passed to be + * managed to another callback function. + */ ath9k_htc_rx_msg(hif_dev->htc_handle, skb, skb->len, USB_REG_IN_PIPE); - - nskb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_ATOMIC); - if (!nskb) { + skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_ATOMIC); + if (!skb) { dev_err(&hif_dev->udev->dev, "ath9k_htc: REG_IN memory allocation failure\n"); - urb->context = NULL; - return; + goto free_rx_buf; } - usb_fill_bulk_urb(urb, hif_dev->udev, - usb_rcvbulkpipe(hif_dev->udev, + rx_buf->skb = skb; + + usb_fill_int_urb(urb, hif_dev->udev, + usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE), - nskb->data, MAX_REG_IN_BUF_SIZE, - ath9k_hif_usb_reg_in_cb, nskb); + skb->data, MAX_REG_IN_BUF_SIZE, + ath9k_hif_usb_reg_in_cb, rx_buf, 1); } resubmit: @@ -735,12 +790,14 @@ resubmit: ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret) { usb_unanchor_urb(urb); - goto free; + goto free_skb; } return; -free: +free_skb: kfree_skb(skb); +free_rx_buf: + kfree(rx_buf); urb->context = NULL; } @@ -749,27 +806,33 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; unsigned long flags; + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); list_for_each_entry_safe(tx_buf, tx_buf_tmp, &hif_dev->tx.tx_buf, list) { - usb_kill_urb(tx_buf->urb); list_del(&tx_buf->list); usb_free_urb(tx_buf->urb); kfree(tx_buf->buf); kfree(tx_buf); } + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); hif_dev->tx.flags |= HIF_USB_TX_FLUSH; spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); list_for_each_entry_safe(tx_buf, tx_buf_tmp, &hif_dev->tx.tx_pending, list) { + usb_get_urb(tx_buf->urb); + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); usb_kill_urb(tx_buf->urb); list_del(&tx_buf->list); usb_free_urb(tx_buf->urb); kfree(tx_buf->buf); kfree(tx_buf); + spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); } + spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); usb_kill_anchored_urbs(&hif_dev->mgmt_submitted); } @@ -786,7 +849,7 @@ static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) init_usb_anchor(&hif_dev->mgmt_submitted); for (i = 0; i < MAX_TX_URB_NUM; i++) { - tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL); + tx_buf = kzalloc(sizeof(*tx_buf), GFP_KERNEL); if (!tx_buf) goto err; @@ -819,12 +882,14 @@ err: static void ath9k_hif_usb_dealloc_rx_urbs(struct hif_device_usb *hif_dev) { usb_kill_anchored_urbs(&hif_dev->rx_submitted); + ath9k_hif_usb_free_rx_remain_skb(hif_dev); } static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev) { - struct urb *urb = NULL; + struct rx_buf *rx_buf = NULL; struct sk_buff *skb = NULL; + struct urb *urb = NULL; int i, ret; init_usb_anchor(&hif_dev->rx_submitted); @@ -832,6 +897,12 @@ static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev) for (i = 0; i < MAX_RX_URB_NUM; i++) { + rx_buf = kzalloc(sizeof(*rx_buf), GFP_KERNEL); + if (!rx_buf) { + ret = -ENOMEM; + goto err_rxb; + } + /* Allocate URB */ urb = usb_alloc_urb(0, GFP_KERNEL); if (urb == NULL) { @@ -846,11 +917,14 @@ static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev) goto err_skb; } + rx_buf->hif_dev = hif_dev; + rx_buf->skb = skb; + usb_fill_bulk_urb(urb, hif_dev->udev, usb_rcvbulkpipe(hif_dev->udev, USB_WLAN_RX_PIPE), skb->data, MAX_RX_BUF_SIZE, - ath9k_hif_usb_rx_cb, skb); + ath9k_hif_usb_rx_cb, rx_buf); /* Anchor URB */ usb_anchor_urb(urb, &hif_dev->rx_submitted); @@ -876,6 +950,8 @@ err_submit: err_skb: usb_free_urb(urb); err_urb: + kfree(rx_buf); +err_rxb: ath9k_hif_usb_dealloc_rx_urbs(hif_dev); return ret; } @@ -887,14 +963,21 @@ static void ath9k_hif_usb_dealloc_reg_in_urbs(struct hif_device_usb *hif_dev) static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev) { - struct urb *urb = NULL; + struct rx_buf *rx_buf = NULL; struct sk_buff *skb = NULL; + struct urb *urb = NULL; int i, ret; init_usb_anchor(&hif_dev->reg_in_submitted); for (i = 0; i < MAX_REG_IN_URB_NUM; i++) { + rx_buf = kzalloc(sizeof(*rx_buf), GFP_KERNEL); + if (!rx_buf) { + ret = -ENOMEM; + goto err_rxb; + } + /* Allocate URB */ urb = usb_alloc_urb(0, GFP_KERNEL); if (urb == NULL) { @@ -909,11 +992,14 @@ static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev) goto err_skb; } - usb_fill_bulk_urb(urb, hif_dev->udev, - usb_rcvbulkpipe(hif_dev->udev, + rx_buf->hif_dev = hif_dev; + rx_buf->skb = skb; + + usb_fill_int_urb(urb, hif_dev->udev, + usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE), skb->data, MAX_REG_IN_BUF_SIZE, - ath9k_hif_usb_reg_in_cb, skb); + ath9k_hif_usb_reg_in_cb, rx_buf, 1); /* Anchor URB */ usb_anchor_urb(urb, &hif_dev->reg_in_submitted); @@ -939,6 +1025,8 @@ err_submit: err_skb: usb_free_urb(urb); err_urb: + kfree(rx_buf); +err_rxb: ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev); return ret; } @@ -969,7 +1057,7 @@ err: return -ENOMEM; } -static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev) +void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev) { usb_kill_anchored_urbs(&hif_dev->regout_submitted); ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev); @@ -996,7 +1084,8 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) err = usb_control_msg(hif_dev->udev, usb_sndctrlpipe(hif_dev->udev, 0), FIRMWARE_DOWNLOAD, 0x40 | USB_DIR_OUT, - addr >> 8, 0, buf, transfer, HZ); + addr >> 8, 0, buf, transfer, + USB_MSG_TIMEOUT); if (err < 0) { kfree(buf); return err; @@ -1019,7 +1108,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) err = usb_control_msg(hif_dev->udev, usb_sndctrlpipe(hif_dev->udev, 0), FIRMWARE_DOWNLOAD_COMP, 0x40 | USB_DIR_OUT, - firm_offset >> 8, 0, NULL, 0, HZ); + firm_offset >> 8, 0, NULL, 0, USB_MSG_TIMEOUT); if (err) return -EIO; @@ -1031,9 +1120,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) { - struct usb_host_interface *alt = &hif_dev->interface->altsetting[0]; - struct usb_endpoint_descriptor *endp; - int ret, idx; + int ret; ret = ath9k_hif_usb_download_fw(hif_dev); if (ret) { @@ -1043,20 +1130,6 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev) return ret; } - /* On downloading the firmware to the target, the USB descriptor of EP4 - * is 'patched' to change the type of the endpoint to Bulk. This will - * bring down CPU usage during the scan period. - */ - for (idx = 0; idx < alt->desc.bNumEndpoints; idx++) { - endp = &alt->endpoint[idx].desc; - if ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_INT) { - endp->bmAttributes &= ~USB_ENDPOINT_XFERTYPE_MASK; - endp->bmAttributes |= USB_ENDPOINT_XFER_BULK; - endp->bInterval = 0; - } - } - /* Alloc URBs */ ret = ath9k_hif_usb_alloc_urbs(hif_dev); if (ret) { @@ -1082,7 +1155,7 @@ static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev) struct device *dev = &hif_dev->udev->dev; struct device *parent = dev->parent; - complete(&hif_dev->fw_done); + complete_all(&hif_dev->fw_done); if (parent) device_lock(parent); @@ -1093,12 +1166,88 @@ static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev) device_unlock(parent); } +static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context); + +/* taken from iwlwifi */ +static int ath9k_hif_request_firmware(struct hif_device_usb *hif_dev, + bool first) +{ + char index[8], *chip; + int ret; + + if (first) { + if (htc_use_dev_fw) { + hif_dev->fw_minor_index = FIRMWARE_MINOR_IDX_MAX + 1; + sprintf(index, "%s", "dev"); + } else { + hif_dev->fw_minor_index = FIRMWARE_MINOR_IDX_MAX; + sprintf(index, "%d", hif_dev->fw_minor_index); + } + } else { + hif_dev->fw_minor_index--; + sprintf(index, "%d", hif_dev->fw_minor_index); + } + + /* test for FW 1.3 */ + if (MAJOR_VERSION_REQ == 1 && hif_dev->fw_minor_index == 3) { + const char *filename; + + if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info)) + filename = FIRMWARE_AR7010_1_1; + else + filename = FIRMWARE_AR9271; + + /* expected fw locations: + * - htc_9271.fw (stable version 1.3, deprecated) + */ + snprintf(hif_dev->fw_name, sizeof(hif_dev->fw_name), + "%s", filename); + + } else if (hif_dev->fw_minor_index < FIRMWARE_MINOR_IDX_MIN) { + dev_err(&hif_dev->udev->dev, "no suitable firmware found!\n"); + + return -ENOENT; + } else { + if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info)) + chip = "7010"; + else + chip = "9271"; + + /* expected fw locations: + * - ath9k_htc/htc_9271-1.dev.0.fw (development version) + * - ath9k_htc/htc_9271-1.4.0.fw (stable version) + */ + snprintf(hif_dev->fw_name, sizeof(hif_dev->fw_name), + "%s/htc_%s-%d.%s.0.fw", HTC_FW_PATH, + chip, MAJOR_VERSION_REQ, index); + } + + ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name, + &hif_dev->udev->dev, GFP_KERNEL, + hif_dev, ath9k_hif_usb_firmware_cb); + if (ret) { + dev_err(&hif_dev->udev->dev, + "ath9k_htc: Async request for firmware %s failed\n", + hif_dev->fw_name); + return ret; + } + + dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n", + hif_dev->fw_name); + + return ret; +} + static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context) { struct hif_device_usb *hif_dev = context; int ret; if (!fw) { + ret = ath9k_hif_request_firmware(hif_dev, false); + if (!ret) + return; + dev_err(&hif_dev->udev->dev, "ath9k_htc: Failed to get firmware %s\n", hif_dev->fw_name); @@ -1131,7 +1280,7 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context) release_firmware(fw); hif_dev->flags |= HIF_USB_READY; - complete(&hif_dev->fw_done); + complete_all(&hif_dev->fw_done); return; @@ -1151,12 +1300,15 @@ err_fw: static int send_eject_command(struct usb_interface *interface) { struct usb_device *udev = interface_to_usbdev(interface); - struct usb_host_interface *iface_desc = &interface->altsetting[0]; + struct usb_host_interface *iface_desc = interface->cur_altsetting; struct usb_endpoint_descriptor *endpoint; unsigned char *cmd; u8 bulk_out_ep; int r; + if (iface_desc->desc.bNumEndpoints < 2) + return -ENODEV; + /* Find bulk out endpoint */ for (r = 1; r >= 0; r--) { endpoint = &iface_desc->endpoint[r].desc; @@ -1188,7 +1340,7 @@ static int send_eject_command(struct usb_interface *interface) dev_info(&udev->dev, "Ejecting storage device...\n"); r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep), - cmd, 31, NULL, 2000); + cmd, 31, NULL, 2 * USB_MSG_TIMEOUT); kfree(cmd); if (r) return r; @@ -1203,10 +1355,24 @@ static int send_eject_command(struct usb_interface *interface) static int ath9k_hif_usb_probe(struct usb_interface *interface, const struct usb_device_id *id) { + struct usb_endpoint_descriptor *bulk_in, *bulk_out, *int_in, *int_out; struct usb_device *udev = interface_to_usbdev(interface); + struct usb_host_interface *alt; struct hif_device_usb *hif_dev; int ret = 0; + /* Verify the expected endpoints are present */ + alt = interface->cur_altsetting; + if (usb_find_common_endpoints(alt, &bulk_in, &bulk_out, &int_in, &int_out) < 0 || + usb_endpoint_num(bulk_in) != USB_WLAN_RX_PIPE || + usb_endpoint_num(bulk_out) != USB_WLAN_TX_PIPE || + usb_endpoint_num(int_in) != USB_REG_IN_PIPE || + usb_endpoint_num(int_out) != USB_REG_OUT_PIPE) { + dev_err(&udev->dev, + "ath9k_htc: Device endpoint numbers are not the expected ones\n"); + return -ENODEV; + } + if (id->driver_info == STORAGE_DEVICE) return send_eject_command(interface); @@ -1228,27 +1394,11 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, init_completion(&hif_dev->fw_done); - /* Find out which firmware to load */ - - if (IS_AR7010_DEVICE(id->driver_info)) - hif_dev->fw_name = FIRMWARE_AR7010_1_1; - else - hif_dev->fw_name = FIRMWARE_AR9271; - - ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name, - &hif_dev->udev->dev, GFP_KERNEL, - hif_dev, ath9k_hif_usb_firmware_cb); - if (ret) { - dev_err(&hif_dev->udev->dev, - "ath9k_htc: Async request for firmware %s failed\n", - hif_dev->fw_name); + ret = ath9k_hif_request_firmware(hif_dev, true); + if (ret) goto err_fw_req; - } - dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n", - hif_dev->fw_name); - - return 0; + return ret; err_fw_req: usb_set_intfdata(interface, NULL); @@ -1268,8 +1418,8 @@ static void ath9k_hif_usb_reboot(struct usb_device *udev) if (!buf) return; - ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, USB_REG_OUT_PIPE), - buf, 4, NULL, HZ); + ret = usb_interrupt_msg(udev, usb_sndintpipe(udev, USB_REG_OUT_PIPE), + buf, 4, NULL, USB_MSG_TIMEOUT); if (ret) dev_err(&udev->dev, "ath9k_htc: USB reboot failed\n"); @@ -1280,7 +1430,7 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface) { struct usb_device *udev = interface_to_usbdev(interface); struct hif_device_usb *hif_dev = usb_get_intfdata(interface); - bool unplugged = (udev->state == USB_STATE_NOTATTACHED) ? true : false; + bool unplugged = udev->state == USB_STATE_NOTATTACHED; if (!hif_dev) return; @@ -1290,12 +1440,13 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface) if (hif_dev->flags & HIF_USB_READY) { ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged); ath9k_htc_hw_free(hif_dev->htc_handle); - ath9k_hif_usb_dev_deinit(hif_dev); } usb_set_intfdata(interface, NULL); - if (!unplugged && (hif_dev->flags & HIF_USB_START)) + /* If firmware was loaded we should drop it + * go back to first stage bootloader. */ + if (!unplugged && (hif_dev->flags & HIF_USB_READY)) ath9k_hif_usb_reboot(udev); kfree(hif_dev); @@ -1316,7 +1467,10 @@ static int ath9k_hif_usb_suspend(struct usb_interface *interface, if (!(hif_dev->flags & HIF_USB_START)) ath9k_htc_suspend(hif_dev->htc_handle); - ath9k_hif_usb_dealloc_urbs(hif_dev); + wait_for_completion(&hif_dev->fw_done); + + if (hif_dev->flags & HIF_USB_READY) + ath9k_hif_usb_dealloc_urbs(hif_dev); return 0; } @@ -1325,31 +1479,31 @@ static int ath9k_hif_usb_resume(struct usb_interface *interface) { struct hif_device_usb *hif_dev = usb_get_intfdata(interface); struct htc_target *htc_handle = hif_dev->htc_handle; - int ret; const struct firmware *fw; + int ret; ret = ath9k_hif_usb_alloc_urbs(hif_dev); if (ret) return ret; - if (hif_dev->flags & HIF_USB_READY) { - /* request cached firmware during suspend/resume cycle */ - ret = request_firmware(&fw, hif_dev->fw_name, - &hif_dev->udev->dev); - if (ret) - goto fail_resume; - - hif_dev->fw_data = fw->data; - hif_dev->fw_size = fw->size; - ret = ath9k_hif_usb_download_fw(hif_dev); - release_firmware(fw); - if (ret) - goto fail_resume; - } else { - ath9k_hif_usb_dealloc_urbs(hif_dev); - return -EIO; + if (!(hif_dev->flags & HIF_USB_READY)) { + ret = -EIO; + goto fail_resume; } + /* request cached firmware during suspend/resume cycle */ + ret = request_firmware(&fw, hif_dev->fw_name, + &hif_dev->udev->dev); + if (ret) + goto fail_resume; + + hif_dev->fw_data = fw->data; + hif_dev->fw_size = fw->size; + ret = ath9k_hif_usb_download_fw(hif_dev); + release_firmware(fw); + if (ret) + goto fail_resume; + mdelay(100); ret = ath9k_htc_resume(htc_handle); diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index 51496e74b83e..b3e66b0485a5 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -17,8 +17,26 @@ #ifndef HTC_USB_H #define HTC_USB_H +/* old firmware images */ +#define FIRMWARE_AR7010_1_1 "htc_7010.fw" +#define FIRMWARE_AR9271 "htc_9271.fw" + +/* supported Major FW version */ #define MAJOR_VERSION_REQ 1 #define MINOR_VERSION_REQ 3 +/* minimal and maximal supported Minor FW version. */ +#define FIRMWARE_MINOR_IDX_MAX 4 +#define FIRMWARE_MINOR_IDX_MIN 3 +#define HTC_FW_PATH "ath9k_htc" + +#define HTC_9271_MODULE_FW HTC_FW_PATH "/htc_9271-" \ + __stringify(MAJOR_VERSION_REQ) \ + "." __stringify(FIRMWARE_MINOR_IDX_MAX) ".0.fw" +#define HTC_7010_MODULE_FW HTC_FW_PATH "/htc_7010-" \ + __stringify(MAJOR_VERSION_REQ) \ + "." __stringify(FIRMWARE_MINOR_IDX_MAX) ".0.fw" + +extern int htc_use_dev_fw; #define IS_AR7010_DEVICE(_v) (((_v) == AR9280_USB) || ((_v) == AR9287_USB)) @@ -53,6 +71,8 @@ #define USB_REG_IN_PIPE 3 #define USB_REG_OUT_PIPE 4 +#define USB_MSG_TIMEOUT 1000 /* (ms) */ + #define HIF_USB_MAX_RXPIPES 2 #define HIF_USB_MAX_TXPIPES 4 @@ -66,6 +86,11 @@ struct tx_buf { struct list_head list; }; +struct rx_buf { + struct sk_buff *skb; + struct hif_device_usb *hif_dev; +}; + #define HIF_USB_TX_STOP BIT(0) #define HIF_USB_TX_FLUSH BIT(1) @@ -101,7 +126,8 @@ struct hif_device_usb { struct usb_anchor reg_in_submitted; struct usb_anchor mgmt_submitted; struct sk_buff *remain_skb; - const char *fw_name; + char fw_name[64]; + int fw_minor_index; int rx_remain_len; int rx_pkt_len; int rx_transfer_len; @@ -112,5 +138,6 @@ struct hif_device_usb { int ath9k_hif_usb_init(void); void ath9k_hif_usb_exit(void); +void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev); #endif /* HTC_USB_H */ diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 055d7c25e090..6c33e898b300 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -39,12 +39,14 @@ #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ #define ATH_DEFAULT_BMISS_LIMIT 10 -#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) #define TSF_TO_TU(_h, _l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) extern struct ieee80211_ops ath9k_htc_ops; extern int htc_modparam_nohwcrypt; +#ifdef CONFIG_MAC80211_LEDS +extern int ath9k_htc_led_blink; +#endif enum htc_phymode { HTC_MODE_11NA = 0, @@ -262,6 +264,8 @@ enum tid_aggr_state { struct ath9k_htc_sta { u8 index; enum tid_aggr_state tid_state[ATH9K_HTC_MAX_TID]; + struct work_struct rc_update_work; + struct ath9k_htc_priv *htc_priv; }; #define ATH9K_HTC_RXBUF 256 @@ -275,9 +279,9 @@ struct ath9k_htc_rxbuf { }; struct ath9k_htc_rx { - int last_rssi; /* FIXME: per-STA */ struct list_head rxbuf; spinlock_t rxbuflock; + bool initialized; }; #define ATH9K_HTC_TX_CLEANUP_INTERVAL 50 /* ms */ @@ -322,17 +326,21 @@ static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) } #ifdef CONFIG_ATH9K_HTC_DEBUGFS - -#define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++) -#define TX_STAT_ADD(c, a) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c += a) -#define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++) -#define RX_STAT_ADD(c, a) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c += a) -#define CAB_STAT_INC priv->debug.tx_stats.cab_queued++ - -#define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++) +#define __STAT_SAFE(hif_dev, expr) do { ((hif_dev)->htc_handle->drv_priv ? (expr) : 0); } while (0) +#define CAB_STAT_INC(priv) do { ((priv)->debug.tx_stats.cab_queued++); } while (0) +#define TX_QSTAT_INC(priv, q) do { ((priv)->debug.tx_stats.queue_stats[q]++); } while (0) + +#define TX_STAT_INC(hif_dev, c) \ + __STAT_SAFE((hif_dev), (hif_dev)->htc_handle->drv_priv->debug.tx_stats.c++) +#define TX_STAT_ADD(hif_dev, c, a) \ + __STAT_SAFE((hif_dev), (hif_dev)->htc_handle->drv_priv->debug.tx_stats.c += a) +#define RX_STAT_INC(hif_dev, c) \ + __STAT_SAFE((hif_dev), (hif_dev)->htc_handle->drv_priv->debug.skbrx_stats.c++) +#define RX_STAT_ADD(hif_dev, c, a) \ + __STAT_SAFE((hif_dev), (hif_dev)->htc_handle->drv_priv->debug.skbrx_stats.c += a) void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, - struct ath_htc_rx_status *rxs); + struct ath_rx_status *rs); struct ath_tx_stats { u32 buf_queued; @@ -345,25 +353,18 @@ struct ath_tx_stats { u32 queue_stats[IEEE80211_NUM_ACS]; }; -struct ath_rx_stats { +struct ath_skbrx_stats { u32 skb_allocated; u32 skb_completed; u32 skb_completed_bytes; u32 skb_dropped; - u32 err_crc; - u32 err_decrypt_crc; - u32 err_mic; - u32 err_pre_delim; - u32 err_post_delim; - u32 err_decrypt_busy; - u32 err_phy; - u32 err_phy_stats[ATH9K_PHYERR_MAX]; }; struct ath9k_debug { struct dentry *debugfs_phy; struct ath_tx_stats tx_stats; struct ath_rx_stats rx_stats; + struct ath_skbrx_stats skbrx_stats; }; void ath9k_htc_get_et_strings(struct ieee80211_hw *hw, @@ -376,16 +377,16 @@ void ath9k_htc_get_et_stats(struct ieee80211_hw *hw, struct ethtool_stats *stats, u64 *data); #else -#define TX_STAT_INC(c) do { } while (0) -#define TX_STAT_ADD(c, a) do { } while (0) -#define RX_STAT_INC(c) do { } while (0) -#define RX_STAT_ADD(c, a) do { } while (0) -#define CAB_STAT_INC do { } while (0) +#define TX_STAT_INC(hif_dev, c) do { } while (0) +#define TX_STAT_ADD(hif_dev, c, a) do { } while (0) +#define RX_STAT_INC(hif_dev, c) do { } while (0) +#define RX_STAT_ADD(hif_dev, c, a) do { } while (0) -#define TX_QSTAT_INC(c) do { } while (0) +#define CAB_STAT_INC(priv) +#define TX_QSTAT_INC(priv, c) static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, - struct ath_htc_rx_status *rxs) + struct ath_rx_status *rs) { } @@ -405,12 +406,18 @@ static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, #define DEFAULT_SWBA_RESPONSE 40 /* in TUs */ #define MIN_SWBA_RESPONSE 10 /* in TUs */ -struct htc_beacon_config { +struct htc_beacon { + enum { + OK, /* no change needed */ + UPDATE, /* update pending */ + COMMIT /* beacon sent, commit change */ + } updateslot; /* slot time update fsm */ + struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF]; - u16 beacon_interval; - u16 dtim_period; - u16 bmiss_timeout; - u32 bmiss_cnt; + u32 bmisscnt; + u32 beaconq; + int slottime; + int slotupdate; }; struct ath_btcoex { @@ -438,13 +445,13 @@ static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv) } #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ -#define OP_INVALID BIT(0) -#define OP_SCANNING BIT(1) -#define OP_ENABLE_BEACON BIT(2) -#define OP_BT_PRIORITY_DETECTED BIT(3) -#define OP_BT_SCAN BIT(4) -#define OP_ANI_RUNNING BIT(5) -#define OP_TSF_RESET BIT(6) +#define OP_BT_PRIORITY_DETECTED 3 +#define OP_BT_SCAN 4 +#define OP_TSF_RESET 6 + +enum htc_op_flags { + HTC_FWFLAG_NO_RMW, +}; struct ath9k_htc_priv { struct device *dev; @@ -484,12 +491,14 @@ struct ath9k_htc_priv { bool reconfig_beacon; unsigned int rxfilter; unsigned long op_flags; + unsigned long fw_flags; struct ath9k_hw_cal_data caldata; - struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; + struct ath_spec_scan_priv spec_priv; spinlock_t beacon_lock; - struct htc_beacon_config cur_beacon_conf; + struct ath_beacon_config cur_beacon_conf; + struct htc_beacon beacon; struct ath9k_htc_rx rx; struct ath9k_htc_tx tx; @@ -505,6 +514,7 @@ struct ath9k_htc_priv { unsigned long ps_usecount; bool ps_enabled; bool ps_idle; + bool initialized; #ifdef CONFIG_MAC80211_LEDS enum led_brightness brightness; @@ -514,7 +524,6 @@ struct ath9k_htc_priv { struct work_struct led_work; #endif - int beaconq; int cabq; int hwq_map[IEEE80211_NUM_ACS]; @@ -528,6 +537,7 @@ struct ath9k_htc_priv { struct ath9k_debug debug; #endif struct mutex mutex; + struct ieee80211_vif *csa_vif; }; static inline void ath_read_cachesize(struct ath_common *common, int *csz) @@ -579,13 +589,14 @@ int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv); void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot); void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv); void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event); -void ath9k_tx_failed_tasklet(unsigned long data); -void ath9k_htc_tx_cleanup_timer(unsigned long data); +void ath9k_tx_failed_tasklet(struct tasklet_struct *t); +void ath9k_htc_tx_cleanup_timer(struct timer_list *t); +bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv); int ath9k_rx_init(struct ath9k_htc_priv *priv); void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); void ath9k_host_rx_init(struct ath9k_htc_priv *priv); -void ath9k_rx_tasklet(unsigned long data); +void ath9k_rx_tasklet(struct tasklet_struct *t); u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv); void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv); @@ -600,10 +611,15 @@ void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw); struct base_eep_header *ath9k_htc_get_eeprom_base(struct ath9k_htc_priv *priv); #ifdef CONFIG_MAC80211_LEDS +void ath9k_configure_leds(struct ath9k_htc_priv *priv); void ath9k_init_leds(struct ath9k_htc_priv *priv); void ath9k_deinit_leds(struct ath9k_htc_priv *priv); void ath9k_led_work(struct work_struct *work); #else +static inline void ath9k_configure_leds(struct ath9k_htc_priv *priv) +{ +} + static inline void ath9k_init_leds(struct ath9k_htc_priv *priv) { } @@ -626,8 +642,12 @@ int ath9k_htc_resume(struct htc_target *htc_handle); #endif #ifdef CONFIG_ATH9K_HTC_DEBUGFS int ath9k_htc_init_debug(struct ath_hw *ah); +void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv); #else static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; }; +static inline void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv) +{ +} #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ #endif /* HTC_H */ diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index e0c03bd64182..81fa7cbad892 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -26,7 +26,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info)); - ath9k_hw_get_txq_props(ah, priv->beaconq, &qi); + ath9k_hw_get_txq_props(ah, priv->beacon.beaconq, &qi); if (priv->ah->opmode == NL80211_IFTYPE_AP || priv->ah->opmode == NL80211_IFTYPE_MESH_POINT) { @@ -45,7 +45,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) * Long slot time : 2x cwmin * Short slot time : 4x cwmin */ - if (ah->slottime == ATH9K_SLOT_TIME_20) + if (ah->slottime == 20) qi.tqi_cwmin = 2*qi_be.tqi_cwmin; else qi.tqi_cwmin = 4*qi_be.tqi_cwmin; @@ -54,235 +54,78 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) } - if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) { + if (!ath9k_hw_set_txq_props(ah, priv->beacon.beaconq, &qi)) { ath_err(ath9k_hw_common(ah), - "Unable to update beacon queue %u!\n", priv->beaconq); + "Unable to update beacon queue %u!\n", priv->beacon.beaconq); } else { - ath9k_hw_resettxqueue(ah, priv->beaconq); + ath9k_hw_resettxqueue(ah, priv->beacon.beaconq); } } - -static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, - struct htc_beacon_config *bss_conf) +/* + * Both nexttbtt and intval have to be in usecs. + */ +static void ath9k_htc_beacon_init(struct ath9k_htc_priv *priv, + struct ath_beacon_config *conf, + bool reset_tsf) { - struct ath_common *common = ath9k_hw_common(priv->ah); - struct ath9k_beacon_state bs; - enum ath9k_int imask = 0; - int dtimperiod, dtimcount, sleepduration; - int cfpperiod, cfpcount, bmiss_timeout; - u32 nexttbtt = 0, intval, tsftu; - __be32 htc_imask = 0; - u64 tsf; - int num_beacons, offset, dtim_dec_count, cfp_dec_count; + struct ath_hw *ah = priv->ah; int ret __attribute__ ((unused)); + __be32 htc_imask = 0; u8 cmd_rsp; - memset(&bs, 0, sizeof(bs)); - - intval = bss_conf->beacon_interval; - bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval); - - /* - * Setup dtim and cfp parameters according to - * last beacon we received (which may be none). - */ - dtimperiod = bss_conf->dtim_period; - if (dtimperiod <= 0) /* NB: 0 if not known */ - dtimperiod = 1; - dtimcount = 1; - if (dtimcount >= dtimperiod) /* NB: sanity check */ - dtimcount = 0; - cfpperiod = 1; /* NB: no PCF support yet */ - cfpcount = 0; - - sleepduration = intval; - if (sleepduration <= 0) - sleepduration = intval; - - /* - * Pull nexttbtt forward to reflect the current - * TSF and calculate dtim+cfp state for the result. - */ - tsf = ath9k_hw_gettsf64(priv->ah); - tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; - - num_beacons = tsftu / intval + 1; - offset = tsftu % intval; - nexttbtt = tsftu - offset; - if (offset) - nexttbtt += intval; - - /* DTIM Beacon every dtimperiod Beacon */ - dtim_dec_count = num_beacons % dtimperiod; - /* CFP every cfpperiod DTIM Beacon */ - cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod; - if (dtim_dec_count) - cfp_dec_count++; - - dtimcount -= dtim_dec_count; - if (dtimcount < 0) - dtimcount += dtimperiod; - - cfpcount -= cfp_dec_count; - if (cfpcount < 0) - cfpcount += cfpperiod; - - 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; - - /* - * Calculate the number of consecutive beacons to miss* before taking - * a BMISS interrupt. The configuration is specified in TU so we only - * need calculate based on the beacon interval. Note that we clamp the - * result to at most 15 beacons. - */ - if (sleepduration > intval) { - bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2; - } else { - bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval); - if (bs.bs_bmissthreshold > 15) - bs.bs_bmissthreshold = 15; - else if (bs.bs_bmissthreshold <= 0) - bs.bs_bmissthreshold = 1; - } - - /* - * Calculate sleep duration. The configuration is given in ms. - * We ensure 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), sleepduration); - if (bs.bs_sleepduration > bs.bs_dtimperiod) - bs.bs_sleepduration = bs.bs_dtimperiod; - - /* TSF out of range threshold fixed at 1 second */ - bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; - - ath_dbg(common, CONFIG, "intval: %u tsf: %llu tsftu: %u\n", - intval, tsf, tsftu); - ath_dbg(common, CONFIG, - "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", - bs.bs_bmissthreshold, bs.bs_sleepduration, - bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); - - /* Set the computed STA beacon timers */ + if (conf->intval >= TU_TO_USEC(DEFAULT_SWBA_RESPONSE)) + ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; + else + ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_set_sta_beacon_timers(priv->ah, &bs); - imask |= ATH9K_INT_BMISS; - htc_imask = cpu_to_be32(imask); + if (reset_tsf) + ath9k_hw_reset_tsf(ah); + ath9k_htc_beaconq_config(priv); + ath9k_hw_beaconinit(ah, conf->nexttbtt, conf->intval); + priv->beacon.bmisscnt = 0; + htc_imask = cpu_to_be32(ah->imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); } -static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, - struct htc_beacon_config *bss_conf) +static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, + struct ath_beacon_config *bss_conf) { - struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_beacon_state bs; enum ath9k_int imask = 0; - u32 nexttbtt, intval, tsftu; __be32 htc_imask = 0; int ret __attribute__ ((unused)); u8 cmd_rsp; - u64 tsf; - - intval = bss_conf->beacon_interval; - intval /= ATH9K_HTC_MAX_BCN_VIF; - nexttbtt = intval; - - /* - * To reduce beacon misses under heavy TX load, - * set the beacon response time to a larger value. - */ - if (intval > DEFAULT_SWBA_RESPONSE) - priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; - else - priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - - if (test_bit(OP_TSF_RESET, &priv->op_flags)) { - ath9k_hw_reset_tsf(priv->ah); - clear_bit(OP_TSF_RESET, &priv->op_flags); - } else { - /* - * Pull nexttbtt forward to reflect the current TSF. - */ - tsf = ath9k_hw_gettsf64(priv->ah); - tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; - do { - nexttbtt += intval; - } while (nexttbtt < tsftu); - } - if (test_bit(OP_ENABLE_BEACON, &priv->op_flags)) - imask |= ATH9K_INT_SWBA; - - ath_dbg(common, CONFIG, - "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d imask: 0x%x\n", - bss_conf->beacon_interval, nexttbtt, - priv->ah->config.sw_beacon_response_time, imask); - - ath9k_htc_beaconq_config(priv); + if (ath9k_cmn_beacon_config_sta(priv->ah, bss_conf, &bs) == -EPERM) + return; WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); - priv->cur_beacon_conf.bmiss_cnt = 0; + ath9k_hw_set_sta_beacon_timers(priv->ah, &bs); + imask |= ATH9K_INT_BMISS; htc_imask = cpu_to_be32(imask); WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); } -static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, - struct htc_beacon_config *bss_conf) +static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, + struct ath_beacon_config *conf) { - struct ath_common *common = ath9k_hw_common(priv->ah); - enum ath9k_int imask = 0; - u32 nexttbtt, intval, tsftu; - __be32 htc_imask = 0; - int ret __attribute__ ((unused)); - u8 cmd_rsp; - u64 tsf; - - intval = bss_conf->beacon_interval; - nexttbtt = intval; - - /* - * Pull nexttbtt forward to reflect the current TSF. - */ - tsf = ath9k_hw_gettsf64(priv->ah); - tsftu = TSF_TO_TU(tsf >> 32, tsf) + FUDGE; - do { - nexttbtt += intval; - } while (nexttbtt < tsftu); - - /* - * Only one IBSS interfce is allowed. - */ - if (intval > DEFAULT_SWBA_RESPONSE) - priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE; - else - priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; + struct ath_hw *ah = priv->ah; + ah->imask = 0; - if (test_bit(OP_ENABLE_BEACON, &priv->op_flags)) - imask |= ATH9K_INT_SWBA; + ath9k_cmn_beacon_config_ap(ah, conf, ATH9K_HTC_MAX_BCN_VIF); + ath9k_htc_beacon_init(priv, conf, false); +} - ath_dbg(common, CONFIG, - "IBSS Beacon config, intval: %d, nexttbtt: %u, resp_time: %d, imask: 0x%x\n", - bss_conf->beacon_interval, nexttbtt, - priv->ah->config.sw_beacon_response_time, imask); +static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, + struct ath_beacon_config *conf) +{ + struct ath_hw *ah = priv->ah; + ah->imask = 0; - WMI_CMD(WMI_DISABLE_INTR_CMDID); - ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval)); - priv->cur_beacon_conf.bmiss_cnt = 0; - htc_imask = cpu_to_be32(imask); - WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); + ath9k_cmn_beacon_config_adhoc(ah, conf); + ath9k_htc_beacon_init(priv, conf, conf->ibss_creator); } void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, @@ -302,7 +145,7 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, spin_lock_bh(&priv->beacon_lock); - vif = priv->cur_beacon_conf.bslot[slot]; + vif = priv->beacon.bslot[slot]; skb = ieee80211_get_buffered_bc(priv->hw, vif); @@ -363,16 +206,16 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, spin_lock_bh(&priv->beacon_lock); - vif = priv->cur_beacon_conf.bslot[slot]; + vif = priv->beacon.bslot[slot]; avp = (struct ath9k_htc_vif *)vif->drv_priv; - if (unlikely(test_bit(OP_SCANNING, &priv->op_flags))) { + if (unlikely(test_bit(ATH_OP_SCANNING, &common->op_flags))) { spin_unlock_bh(&priv->beacon_lock); return; } /* Get a new beacon */ - beacon = ieee80211_beacon_get(priv->hw, vif); + beacon = ieee80211_beacon_get(priv->hw, vif, 0); if (!beacon) { spin_unlock_bh(&priv->beacon_lock); return; @@ -414,6 +257,8 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, } spin_unlock_bh(&priv->beacon_lock); + + ath9k_htc_csa_is_finished(priv); } static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv, @@ -445,9 +290,12 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, struct ath_common *common = ath9k_hw_common(priv->ah); int slot; + if (!priv->cur_beacon_conf.enable_beacon) + return; + if (swba->beacon_pending != 0) { - priv->cur_beacon_conf.bmiss_cnt++; - if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) { + priv->beacon.bmisscnt++; + if (priv->beacon.bmisscnt > BSTUCK_THRESHOLD) { ath_dbg(common, BSTUCK, "Beacon stuck, HW reset\n"); ieee80211_queue_work(priv->hw, &priv->fatal_work); @@ -455,16 +303,16 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, return; } - if (priv->cur_beacon_conf.bmiss_cnt) { + if (priv->beacon.bmisscnt) { ath_dbg(common, BSTUCK, "Resuming beacon xmit after %u misses\n", - priv->cur_beacon_conf.bmiss_cnt); - priv->cur_beacon_conf.bmiss_cnt = 0; + priv->beacon.bmisscnt); + priv->beacon.bmisscnt = 0; } slot = ath9k_htc_choose_bslot(priv, swba); spin_lock_bh(&priv->beacon_lock); - if (priv->cur_beacon_conf.bslot[slot] == NULL) { + if (priv->beacon.bslot[slot] == NULL) { spin_unlock_bh(&priv->beacon_lock); return; } @@ -483,13 +331,13 @@ void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, spin_lock_bh(&priv->beacon_lock); for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) { - if (priv->cur_beacon_conf.bslot[i] == NULL) { + if (priv->beacon.bslot[i] == NULL) { avp->bslot = i; break; } } - priv->cur_beacon_conf.bslot[avp->bslot] = vif; + priv->beacon.bslot[avp->bslot] = vif; spin_unlock_bh(&priv->beacon_lock); ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n", @@ -503,7 +351,7 @@ void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; spin_lock_bh(&priv->beacon_lock); - priv->cur_beacon_conf.bslot[avp->bslot] = NULL; + priv->beacon.bslot[avp->bslot] = NULL; spin_unlock_bh(&priv->beacon_lock); ath_dbg(common, CONFIG, "Removed interface at beacon slot: %d\n", @@ -519,7 +367,7 @@ void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, { struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; u64 tsfadjust; if (avp->bslot == 0) @@ -539,7 +387,7 @@ void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - bool *beacon_configured = (bool *)data; + bool *beacon_configured = data; struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; if (vif->type == NL80211_IFTYPE_STATION && @@ -551,7 +399,7 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(priv->ah); - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; bool beacon_configured; @@ -606,7 +454,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(priv->ah); - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; @@ -642,7 +490,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); - struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &priv->cur_beacon_conf; switch (priv->ah->opmode) { case NL80211_IFTYPE_STATION: @@ -660,3 +508,20 @@ void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv) return; } } + +bool ath9k_htc_csa_is_finished(struct ath9k_htc_priv *priv) +{ + struct ieee80211_vif *vif; + + vif = priv->csa_vif; + if (!vif || !vif->bss_conf.csa_active) + return false; + + if (!ieee80211_beacon_cntdwn_is_complete(vif, 0)) + return false; + + ieee80211_csa_finish(vif, 0); + + priv->csa_vif = NULL; + return true; +} diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index c1b45e2f8481..9437d69877cc 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -37,29 +37,29 @@ static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf, ath9k_htc_ps_restore(priv); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "RX", - be32_to_cpu(cmd_rsp.rx)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "RX", + be32_to_cpu(cmd_rsp.rx)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "RXORN", - be32_to_cpu(cmd_rsp.rxorn)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "RXORN", + be32_to_cpu(cmd_rsp.rxorn)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "RXEOL", - be32_to_cpu(cmd_rsp.rxeol)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "RXEOL", + be32_to_cpu(cmd_rsp.rxeol)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "TXURN", - be32_to_cpu(cmd_rsp.txurn)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "TXURN", + be32_to_cpu(cmd_rsp.txurn)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "TXTO", - be32_to_cpu(cmd_rsp.txto)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "TXTO", + be32_to_cpu(cmd_rsp.txto)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "CST", - be32_to_cpu(cmd_rsp.cst)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "CST", + be32_to_cpu(cmd_rsp.cst)); if (len > sizeof(buf)) len = sizeof(buf); @@ -95,41 +95,41 @@ static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf, ath9k_htc_ps_restore(priv); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "Xretries", - be32_to_cpu(cmd_rsp.xretries)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "Xretries", + be32_to_cpu(cmd_rsp.xretries)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "FifoErr", - be32_to_cpu(cmd_rsp.fifoerr)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "FifoErr", + be32_to_cpu(cmd_rsp.fifoerr)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "Filtered", - be32_to_cpu(cmd_rsp.filtered)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "Filtered", + be32_to_cpu(cmd_rsp.filtered)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "TimerExp", - be32_to_cpu(cmd_rsp.timer_exp)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "TimerExp", + be32_to_cpu(cmd_rsp.timer_exp)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "ShortRetries", - be32_to_cpu(cmd_rsp.shortretries)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "ShortRetries", + be32_to_cpu(cmd_rsp.shortretries)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "LongRetries", - be32_to_cpu(cmd_rsp.longretries)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "LongRetries", + be32_to_cpu(cmd_rsp.longretries)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "QueueNull", - be32_to_cpu(cmd_rsp.qnull)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "QueueNull", + be32_to_cpu(cmd_rsp.qnull)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "EncapFail", - be32_to_cpu(cmd_rsp.encap_fail)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "EncapFail", + be32_to_cpu(cmd_rsp.encap_fail)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "NoBuf", - be32_to_cpu(cmd_rsp.nobuf)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "NoBuf", + be32_to_cpu(cmd_rsp.nobuf)); if (len > sizeof(buf)) len = sizeof(buf); @@ -165,17 +165,17 @@ static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf, ath9k_htc_ps_restore(priv); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "NoBuf", - be32_to_cpu(cmd_rsp.nobuf)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "NoBuf", + be32_to_cpu(cmd_rsp.nobuf)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "HostSend", - be32_to_cpu(cmd_rsp.host_send)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "HostSend", + be32_to_cpu(cmd_rsp.host_send)); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "HostDone", - be32_to_cpu(cmd_rsp.host_done)); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "HostDone", + be32_to_cpu(cmd_rsp.host_done)); if (len > sizeof(buf)) len = sizeof(buf); @@ -197,37 +197,37 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, char buf[512]; unsigned int len = 0; - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "Buffers queued", - priv->debug.tx_stats.buf_queued); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "Buffers completed", - priv->debug.tx_stats.buf_completed); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs queued", - priv->debug.tx_stats.skb_queued); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs success", - priv->debug.tx_stats.skb_success); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "SKBs failed", - priv->debug.tx_stats.skb_failed); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "CAB queued", - priv->debug.tx_stats.cab_queued); - - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "BE queued", - priv->debug.tx_stats.queue_stats[IEEE80211_AC_BE]); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "BK queued", - priv->debug.tx_stats.queue_stats[IEEE80211_AC_BK]); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "VI queued", - priv->debug.tx_stats.queue_stats[IEEE80211_AC_VI]); - len += snprintf(buf + len, sizeof(buf) - len, - "%20s : %10u\n", "VO queued", - priv->debug.tx_stats.queue_stats[IEEE80211_AC_VO]); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "Buffers queued", + priv->debug.tx_stats.buf_queued); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "Buffers completed", + priv->debug.tx_stats.buf_completed); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs queued", + priv->debug.tx_stats.skb_queued); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs success", + priv->debug.tx_stats.skb_success); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "SKBs failed", + priv->debug.tx_stats.skb_failed); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "CAB queued", + priv->debug.tx_stats.cab_queued); + + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "BE queued", + priv->debug.tx_stats.queue_stats[IEEE80211_AC_BE]); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "BK queued", + priv->debug.tx_stats.queue_stats[IEEE80211_AC_BK]); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "VI queued", + priv->debug.tx_stats.queue_stats[IEEE80211_AC_VI]); + len += scnprintf(buf + len, sizeof(buf) - len, + "%20s : %10u\n", "VO queued", + priv->debug.tx_stats.queue_stats[IEEE80211_AC_VO]); if (len > sizeof(buf)) len = sizeof(buf); @@ -243,39 +243,14 @@ static const struct file_operations fops_xmit = { }; void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, - struct ath_htc_rx_status *rxs) + struct ath_rx_status *rs) { -#define RX_PHY_ERR_INC(c) priv->debug.rx_stats.err_phy_stats[c]++ - - if (rxs->rs_status & ATH9K_RXERR_CRC) - priv->debug.rx_stats.err_crc++; - if (rxs->rs_status & ATH9K_RXERR_DECRYPT) - priv->debug.rx_stats.err_decrypt_crc++; - if (rxs->rs_status & ATH9K_RXERR_MIC) - priv->debug.rx_stats.err_mic++; - if (rxs->rs_status & ATH9K_RX_DELIM_CRC_PRE) - priv->debug.rx_stats.err_pre_delim++; - if (rxs->rs_status & ATH9K_RX_DELIM_CRC_POST) - priv->debug.rx_stats.err_post_delim++; - if (rxs->rs_status & ATH9K_RX_DECRYPT_BUSY) - priv->debug.rx_stats.err_decrypt_busy++; - - if (rxs->rs_status & ATH9K_RXERR_PHY) { - priv->debug.rx_stats.err_phy++; - if (rxs->rs_phyerr < ATH9K_PHYERR_MAX) - RX_PHY_ERR_INC(rxs->rs_phyerr); - } - -#undef RX_PHY_ERR_INC + ath9k_cmn_debug_stat_rx(&priv->debug.rx_stats, rs); } -static ssize_t read_file_recv(struct file *file, char __user *user_buf, +static ssize_t read_file_skb_rx(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { -#define PHY_ERR(s, p) \ - len += snprintf(buf + len, size - len, "%20s : %10u\n", s, \ - priv->debug.rx_stats.err_phy_stats[p]); - struct ath9k_htc_priv *priv = file->private_data; char *buf; unsigned int len = 0, size = 1500; @@ -285,65 +260,15 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, if (buf == NULL) return -ENOMEM; - len += snprintf(buf + len, size - len, - "%20s : %10u\n", "SKBs allocated", - priv->debug.rx_stats.skb_allocated); - len += snprintf(buf + len, size - len, - "%20s : %10u\n", "SKBs completed", - priv->debug.rx_stats.skb_completed); - len += snprintf(buf + len, size - len, - "%20s : %10u\n", "SKBs Dropped", - priv->debug.rx_stats.skb_dropped); - - len += snprintf(buf + len, size - len, - "%20s : %10u\n", "CRC ERR", - priv->debug.rx_stats.err_crc); - len += snprintf(buf + len, size - len, - "%20s : %10u\n", "DECRYPT CRC ERR", - priv->debug.rx_stats.err_decrypt_crc); - len += snprintf(buf + len, size - len, - "%20s : %10u\n", "MIC ERR", - priv->debug.rx_stats.err_mic); - len += snprintf(buf + len, size - len, - "%20s : %10u\n", "PRE-DELIM CRC ERR", - priv->debug.rx_stats.err_pre_delim); - len += snprintf(buf + len, size - len, - "%20s : %10u\n", "POST-DELIM CRC ERR", - priv->debug.rx_stats.err_post_delim); - len += snprintf(buf + len, size - len, - "%20s : %10u\n", "DECRYPT BUSY ERR", - priv->debug.rx_stats.err_decrypt_busy); - len += snprintf(buf + len, size - len, - "%20s : %10u\n", "TOTAL PHY ERR", - priv->debug.rx_stats.err_phy); - - - PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); - PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); - PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); - PHY_ERR("RATE", ATH9K_PHYERR_RATE); - PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH); - PHY_ERR("RADAR", ATH9K_PHYERR_RADAR); - PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE); - PHY_ERR("TOR", ATH9K_PHYERR_TOR); - PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING); - PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); - PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); - PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); - PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP); - PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE); - PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART); - PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT); - PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING); - PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC); - PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL); - PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE); - PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART); - PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); - PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP); - PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR); - PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); - PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL); + len += scnprintf(buf + len, size - len, + "%20s : %10u\n", "SKBs allocated", + priv->debug.skbrx_stats.skb_allocated); + len += scnprintf(buf + len, size - len, + "%20s : %10u\n", "SKBs completed", + priv->debug.skbrx_stats.skb_completed); + len += scnprintf(buf + len, size - len, + "%20s : %10u\n", "SKBs Dropped", + priv->debug.skbrx_stats.skb_dropped); if (len > size) len = size; @@ -352,12 +277,10 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, kfree(buf); return retval; - -#undef PHY_ERR } -static const struct file_operations fops_recv = { - .read = read_file_recv, +static const struct file_operations fops_skb_rx = { + .read = read_file_skb_rx, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, @@ -368,26 +291,15 @@ static ssize_t read_file_slot(struct file *file, char __user *user_buf, { struct ath9k_htc_priv *priv = file->private_data; char buf[512]; - unsigned int len = 0; + unsigned int len; spin_lock_bh(&priv->tx.tx_lock); - - len += snprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : "); - - len += bitmap_scnprintf(buf + len, sizeof(buf) - len, - priv->tx.tx_slot, MAX_TX_BUF_NUM); - - len += snprintf(buf + len, sizeof(buf) - len, "\n"); - - len += snprintf(buf + len, sizeof(buf) - len, + len = scnprintf(buf, sizeof(buf), + "TX slot bitmap : %*pb\n" "Used slots : %d\n", + MAX_TX_BUF_NUM, priv->tx.tx_slot, bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM)); - spin_unlock_bh(&priv->tx.tx_lock); - - if (len > sizeof(buf)) - len = sizeof(buf); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -405,30 +317,30 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf, char buf[512]; unsigned int len = 0; - len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", - "Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue)); + len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue)); - len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", - "Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue)); + len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue)); - len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", - "Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue)); + len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue)); - len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", - "Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue)); + len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue)); - len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", - "Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue)); + len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue)); - len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", - "Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue)); + len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue)); - len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", - "Failed queue", skb_queue_len(&priv->tx.tx_failed)); + len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Failed queue", skb_queue_len(&priv->tx.tx_failed)); spin_lock_bh(&priv->tx.tx_lock); - len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", - "Queued count", priv->tx.queued_cnt); + len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", + "Queued count", priv->tx.queued_cnt); spin_unlock_bh(&priv->tx.tx_lock); if (len > sizeof(buf)) @@ -463,16 +375,11 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf, struct ath9k_htc_priv *priv = file->private_data; struct ath_common *common = ath9k_hw_common(priv->ah); unsigned long mask; - char buf[32]; - ssize_t len; - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; + ssize_t ret; - buf[len] = '\0'; - if (kstrtoul(buf, 0, &mask)) - return -EINVAL; + ret = kstrtoul_from_user(user_buf, count, 0, &mask); + if (ret) + return ret; common->debug_mask = mask; return count; @@ -486,423 +393,6 @@ static const struct file_operations fops_debug = { .llseek = default_llseek, }; -static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath9k_htc_priv *priv = file->private_data; - struct ath_common *common = ath9k_hw_common(priv->ah); - struct base_eep_header *pBase = NULL; - unsigned int len = 0, size = 1500; - ssize_t retval = 0; - char *buf; - - pBase = ath9k_htc_get_eeprom_base(priv); - - if (pBase == NULL) { - ath_err(common, "Unknown EEPROM type\n"); - return 0; - } - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - len += snprintf(buf + len, size - len, - "%20s : %10d\n", "Major Version", - pBase->version >> 12); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", "Minor Version", - pBase->version & 0xFFF); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", "Checksum", - pBase->checksum); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", "Length", - pBase->length); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", "RegDomain1", - pBase->regDmn[0]); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", "RegDomain2", - pBase->regDmn[1]); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", - "TX Mask", pBase->txMask); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", - "RX Mask", pBase->rxMask); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", - "Allow 5GHz", - !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", - "Allow 2GHz", - !!(pBase->opCapFlags & AR5416_OPFLAGS_11G)); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", - "Disable 2GHz HT20", - !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT20)); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", - "Disable 2GHz HT40", - !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT40)); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", - "Disable 5Ghz HT20", - !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT20)); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", - "Disable 5Ghz HT40", - !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT40)); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", - "Big Endian", - !!(pBase->eepMisc & 0x01)); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", - "Cal Bin Major Ver", - (pBase->binBuildNumber >> 24) & 0xFF); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", - "Cal Bin Minor Ver", - (pBase->binBuildNumber >> 16) & 0xFF); - len += snprintf(buf + len, size - len, - "%20s : %10d\n", - "Cal Bin Build", - (pBase->binBuildNumber >> 8) & 0xFF); - - /* - * UB91 specific data. - */ - if (AR_SREV_9271(priv->ah)) { - struct base_eep_header_4k *pBase4k = - &priv->ah->eeprom.map4k.baseEepHeader; - - len += snprintf(buf + len, size - len, - "%20s : %10d\n", - "TX Gain type", - pBase4k->txGainType); - } - - /* - * UB95 specific data. - */ - if (priv->ah->hw_version.usbdev == AR9287_USB) { - struct base_eep_ar9287_header *pBase9287 = - &priv->ah->eeprom.map9287.baseEepHeader; - - len += snprintf(buf + len, size - len, - "%20s : %10ddB\n", - "Power Table Offset", - pBase9287->pwrTableOffset); - - len += snprintf(buf + len, size - len, - "%20s : %10d\n", - "OpenLoop Power Ctrl", - pBase9287->openLoopPwrCntl); - } - - len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", - pBase->macAddr); - if (len > size) - len = size; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; -} - -static const struct file_operations fops_base_eeprom = { - .read = read_file_base_eeprom, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - -static ssize_t read_4k_modal_eeprom(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ -#define PR_EEP(_s, _val) \ - do { \ - len += snprintf(buf + len, size - len, "%20s : %10d\n", \ - _s, (_val)); \ - } while (0) - - struct ath9k_htc_priv *priv = file->private_data; - struct modal_eep_4k_header *pModal = &priv->ah->eeprom.map4k.modalHeader; - unsigned int len = 0, size = 2048; - ssize_t retval = 0; - char *buf; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); - PR_EEP("Ant. Common Control", pModal->antCtrlCommon); - PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); - PR_EEP("Switch Settle", pModal->switchSettling); - PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); - PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); - PR_EEP("ADC Desired size", pModal->adcDesiredSize); - PR_EEP("PGA Desired size", pModal->pgaDesiredSize); - PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]); - PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); - PR_EEP("txEndToRxOn", pModal->txEndToRxOn); - PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); - PR_EEP("CCA Threshold)", pModal->thresh62); - PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); - PR_EEP("xpdGain", pModal->xpdGain); - PR_EEP("External PD", pModal->xpd); - PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); - PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); - PR_EEP("pdGainOverlap", pModal->pdGainOverlap); - PR_EEP("O/D Bias Version", pModal->version); - PR_EEP("CCK OutputBias", pModal->ob_0); - PR_EEP("BPSK OutputBias", pModal->ob_1); - PR_EEP("QPSK OutputBias", pModal->ob_2); - PR_EEP("16QAM OutputBias", pModal->ob_3); - PR_EEP("64QAM OutputBias", pModal->ob_4); - PR_EEP("CCK Driver1_Bias", pModal->db1_0); - PR_EEP("BPSK Driver1_Bias", pModal->db1_1); - PR_EEP("QPSK Driver1_Bias", pModal->db1_2); - PR_EEP("16QAM Driver1_Bias", pModal->db1_3); - PR_EEP("64QAM Driver1_Bias", pModal->db1_4); - PR_EEP("CCK Driver2_Bias", pModal->db2_0); - PR_EEP("BPSK Driver2_Bias", pModal->db2_1); - PR_EEP("QPSK Driver2_Bias", pModal->db2_2); - PR_EEP("16QAM Driver2_Bias", pModal->db2_3); - PR_EEP("64QAM Driver2_Bias", pModal->db2_4); - PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); - PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); - PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); - PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); - PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); - PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); - PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); - PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]); - PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]); - PR_EEP("Ant. Diversity ctl1", pModal->antdiv_ctl1); - PR_EEP("Ant. Diversity ctl2", pModal->antdiv_ctl2); - PR_EEP("TX Diversity", pModal->tx_diversity); - - if (len > size) - len = size; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; - -#undef PR_EEP -} - -static ssize_t read_def_modal_eeprom(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ -#define PR_EEP(_s, _val) \ - do { \ - if (pBase->opCapFlags & AR5416_OPFLAGS_11G) { \ - pModal = &priv->ah->eeprom.def.modalHeader[1]; \ - len += snprintf(buf + len, size - len, "%20s : %8d%7s", \ - _s, (_val), "|"); \ - } \ - if (pBase->opCapFlags & AR5416_OPFLAGS_11A) { \ - pModal = &priv->ah->eeprom.def.modalHeader[0]; \ - len += snprintf(buf + len, size - len, "%9d\n", \ - (_val)); \ - } \ - } while (0) - - struct ath9k_htc_priv *priv = file->private_data; - struct base_eep_header *pBase = &priv->ah->eeprom.def.baseEepHeader; - struct modal_eep_header *pModal = NULL; - unsigned int len = 0, size = 3500; - ssize_t retval = 0; - char *buf; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - len += snprintf(buf + len, size - len, - "%31s %15s\n", "2G", "5G"); - len += snprintf(buf + len, size - len, - "%32s %16s\n", "====", "====\n"); - - PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); - PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]); - PR_EEP("Chain2 Ant. Control", pModal->antCtrlChain[2]); - PR_EEP("Ant. Common Control", pModal->antCtrlCommon); - PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); - PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]); - PR_EEP("Chain2 Ant. Gain", pModal->antennaGainCh[2]); - PR_EEP("Switch Settle", pModal->switchSettling); - PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); - PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]); - PR_EEP("Chain2 TxRxAtten", pModal->txRxAttenCh[2]); - PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); - PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]); - PR_EEP("Chain2 RxTxMargin", pModal->rxTxMarginCh[2]); - PR_EEP("ADC Desired size", pModal->adcDesiredSize); - PR_EEP("PGA Desired size", pModal->pgaDesiredSize); - PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]); - PR_EEP("Chain1 xlna Gain", pModal->xlnaGainCh[1]); - PR_EEP("Chain2 xlna Gain", pModal->xlnaGainCh[2]); - PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); - PR_EEP("txEndToRxOn", pModal->txEndToRxOn); - PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); - PR_EEP("CCA Threshold)", pModal->thresh62); - PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); - PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]); - PR_EEP("Chain2 NF Threshold", pModal->noiseFloorThreshCh[2]); - PR_EEP("xpdGain", pModal->xpdGain); - PR_EEP("External PD", pModal->xpd); - PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); - PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]); - PR_EEP("Chain2 I Coefficient", pModal->iqCalICh[2]); - PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); - PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]); - PR_EEP("Chain2 Q Coefficient", pModal->iqCalQCh[2]); - PR_EEP("pdGainOverlap", pModal->pdGainOverlap); - PR_EEP("Chain0 OutputBias", pModal->ob); - PR_EEP("Chain0 DriverBias", pModal->db); - PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); - PR_EEP("2chain pwr decrease", pModal->pwrDecreaseFor2Chain); - PR_EEP("3chain pwr decrease", pModal->pwrDecreaseFor3Chain); - PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); - PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); - PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); - PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); - PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]); - PR_EEP("Chain2 bswAtten", pModal->bswAtten[2]); - PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); - PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]); - PR_EEP("Chain2 bswMargin", pModal->bswMargin[2]); - PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); - PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]); - PR_EEP("Chain1 xatten2Db", pModal->xatten2Db[1]); - PR_EEP("Chain2 xatten2Db", pModal->xatten2Db[2]); - PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]); - PR_EEP("Chain1 xatten2Margin", pModal->xatten2Margin[1]); - PR_EEP("Chain2 xatten2Margin", pModal->xatten2Margin[2]); - PR_EEP("Chain1 OutputBias", pModal->ob_ch1); - PR_EEP("Chain1 DriverBias", pModal->db_ch1); - PR_EEP("LNA Control", pModal->lna_ctl); - PR_EEP("XPA Bias Freq0", pModal->xpaBiasLvlFreq[0]); - PR_EEP("XPA Bias Freq1", pModal->xpaBiasLvlFreq[1]); - PR_EEP("XPA Bias Freq2", pModal->xpaBiasLvlFreq[2]); - - if (len > size) - len = size; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; - -#undef PR_EEP -} - -static ssize_t read_9287_modal_eeprom(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ -#define PR_EEP(_s, _val) \ - do { \ - len += snprintf(buf + len, size - len, "%20s : %10d\n", \ - _s, (_val)); \ - } while (0) - - struct ath9k_htc_priv *priv = file->private_data; - struct modal_eep_ar9287_header *pModal = &priv->ah->eeprom.map9287.modalHeader; - unsigned int len = 0, size = 3000; - ssize_t retval = 0; - char *buf; - - buf = kzalloc(size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); - PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]); - PR_EEP("Ant. Common Control", pModal->antCtrlCommon); - PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); - PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]); - PR_EEP("Switch Settle", pModal->switchSettling); - PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); - PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]); - PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); - PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]); - PR_EEP("ADC Desired size", pModal->adcDesiredSize); - PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); - PR_EEP("txEndToRxOn", pModal->txEndToRxOn); - PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); - PR_EEP("CCA Threshold)", pModal->thresh62); - PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); - PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]); - PR_EEP("xpdGain", pModal->xpdGain); - PR_EEP("External PD", pModal->xpd); - PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); - PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]); - PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); - PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]); - PR_EEP("pdGainOverlap", pModal->pdGainOverlap); - PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); - PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); - PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); - PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); - PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); - PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]); - PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); - PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]); - PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); - PR_EEP("AR92x7 Version", pModal->version); - PR_EEP("DriverBias1", pModal->db1); - PR_EEP("DriverBias2", pModal->db1); - PR_EEP("CCK OutputBias", pModal->ob_cck); - PR_EEP("PSK OutputBias", pModal->ob_psk); - PR_EEP("QAM OutputBias", pModal->ob_qam); - PR_EEP("PAL_OFF OutputBias", pModal->ob_pal_off); - - if (len > size) - len = size; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - - return retval; - -#undef PR_EEP -} - -static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath9k_htc_priv *priv = file->private_data; - - if (AR_SREV_9271(priv->ah)) - return read_4k_modal_eeprom(file, user_buf, count, ppos); - else if (priv->ah->hw_version.usbdev == AR9280_USB) - return read_def_modal_eeprom(file, user_buf, count, ppos); - else if (priv->ah->hw_version.usbdev == AR9287_USB) - return read_9287_modal_eeprom(file, user_buf, count, ppos); - - return 0; -} - -static const struct file_operations fops_modal_eeprom = { - .read = read_file_modal_eeprom, - .open = simple_open, - .owner = THIS_MODULE, - .llseek = default_llseek, -}; - - /* Ethtool support for get-stats */ #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO" static const char ath9k_htc_gstrings_stats[][ETH_GSTRING_LEN] = { @@ -933,7 +423,7 @@ void ath9k_htc_get_et_strings(struct ieee80211_hw *hw, u32 sset, u8 *data) { if (sset == ETH_SS_STATS) - memcpy(data, *ath9k_htc_gstrings_stats, + memcpy(data, ath9k_htc_gstrings_stats, sizeof(ath9k_htc_gstrings_stats)); } @@ -947,6 +437,8 @@ int ath9k_htc_get_et_sset_count(struct ieee80211_hw *hw, #define STXBASE priv->debug.tx_stats #define SRXBASE priv->debug.rx_stats +#define SKBTXBASE priv->debug.tx_stats +#define SKBRXBASE priv->debug.skbrx_stats #define ASTXQ(a) \ data[i++] = STXBASE.a[IEEE80211_AC_BE]; \ data[i++] = STXBASE.a[IEEE80211_AC_BK]; \ @@ -960,59 +452,66 @@ void ath9k_htc_get_et_stats(struct ieee80211_hw *hw, struct ath9k_htc_priv *priv = hw->priv; int i = 0; - data[i++] = STXBASE.skb_success; - data[i++] = STXBASE.skb_success_bytes; - data[i++] = SRXBASE.skb_completed; - data[i++] = SRXBASE.skb_completed_bytes; + data[i++] = SKBTXBASE.skb_success; + data[i++] = SKBTXBASE.skb_success_bytes; + data[i++] = SKBRXBASE.skb_completed; + data[i++] = SKBRXBASE.skb_completed_bytes; ASTXQ(queue_stats); - data[i++] = SRXBASE.err_crc; - data[i++] = SRXBASE.err_decrypt_crc; - data[i++] = SRXBASE.err_phy; - data[i++] = SRXBASE.err_mic; - data[i++] = SRXBASE.err_pre_delim; - data[i++] = SRXBASE.err_post_delim; - data[i++] = SRXBASE.err_decrypt_busy; + data[i++] = SRXBASE.crc_err; + data[i++] = SRXBASE.decrypt_crc_err; + data[i++] = SRXBASE.phy_err; + data[i++] = SRXBASE.mic_err; + data[i++] = SRXBASE.pre_delim_crc_err; + data[i++] = SRXBASE.post_delim_crc_err; + data[i++] = SRXBASE.decrypt_busy_err; - data[i++] = SRXBASE.err_phy_stats[ATH9K_PHYERR_RADAR]; - data[i++] = SRXBASE.err_phy_stats[ATH9K_PHYERR_OFDM_TIMING]; - data[i++] = SRXBASE.err_phy_stats[ATH9K_PHYERR_CCK_TIMING]; + data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_RADAR]; + data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_OFDM_TIMING]; + data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_CCK_TIMING]; WARN_ON(i != ATH9K_HTC_SSTATS_LEN); } +void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv) +{ + ath9k_cmn_spectral_deinit_debug(&priv->spec_priv); +} int ath9k_htc_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME, priv->hw->wiphy->debugfsdir); - if (!priv->debug.debugfs_phy) - return -ENOMEM; - debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy, + ath9k_cmn_spectral_init_debug(&priv->spec_priv, priv->debug.debugfs_phy); + + debugfs_create_file("tgt_int_stats", 0400, priv->debug.debugfs_phy, priv, &fops_tgt_int_stats); - debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy, + debugfs_create_file("tgt_tx_stats", 0400, priv->debug.debugfs_phy, priv, &fops_tgt_tx_stats); - debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy, + debugfs_create_file("tgt_rx_stats", 0400, priv->debug.debugfs_phy, priv, &fops_tgt_rx_stats); - debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy, + debugfs_create_file("xmit", 0400, priv->debug.debugfs_phy, priv, &fops_xmit); - debugfs_create_file("recv", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_recv); - debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy, + debugfs_create_file("skb_rx", 0400, priv->debug.debugfs_phy, + priv, &fops_skb_rx); + + ath9k_cmn_debug_recv(priv->debug.debugfs_phy, &priv->debug.rx_stats); + ath9k_cmn_debug_phy_err(priv->debug.debugfs_phy, &priv->debug.rx_stats); + + debugfs_create_file("slot", 0400, priv->debug.debugfs_phy, priv, &fops_slot); - debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy, + debugfs_create_file("queue", 0400, priv->debug.debugfs_phy, priv, &fops_queue); - debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy, + debugfs_create_file("debug", 0600, priv->debug.debugfs_phy, priv, &fops_debug); - debugfs_create_file("base_eeprom", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_base_eeprom); - debugfs_create_file("modal_eeprom", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_modal_eeprom); + + ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah); + ath9k_cmn_debug_modal_eeprom(priv->debug.debugfs_phy, priv->ah); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 105582d6b714..ecb848b60725 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -253,6 +253,19 @@ void ath9k_deinit_leds(struct ath9k_htc_priv *priv) ath9k_led_brightness(&priv->led_cdev, LED_OFF); led_classdev_unregister(&priv->led_cdev); cancel_work_sync(&priv->led_work); + + ath9k_hw_gpio_free(priv->ah, priv->ah->led_pin); +} + + +void ath9k_configure_leds(struct ath9k_htc_priv *priv) +{ + /* Configure gpio 1 for output */ + ath9k_hw_gpio_request_out(priv->ah, priv->ah->led_pin, + "ath9k-led", + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + /* LED off, active low */ + ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); } void ath9k_init_leds(struct ath9k_htc_priv *priv) @@ -268,11 +281,11 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv) else priv->ah->led_pin = ATH_LED_PIN_DEF; - /* Configure gpio 1 for output */ - ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin, - AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - /* LED off, active low */ - ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); + if (!ath9k_htc_led_blink) + priv->led_cdev.default_trigger = + ieee80211_get_radio_led_name(priv->hw); + + ath9k_configure_leds(priv); snprintf(priv->led_name, sizeof(priv->led_name), "ath9k_htc-%s", wiphy_name(priv->hw->wiphy)); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 71a183ffc77f..3633f9eb2c55 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -34,94 +34,19 @@ static int ath9k_htc_btcoex_enable; module_param_named(btcoex_enable, ath9k_htc_btcoex_enable, int, 0444); MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); -#define CHAN2G(_freq, _idx) { \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -#define CHAN5G(_freq, _idx) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -static struct ieee80211_channel ath9k_2ghz_channels[] = { - CHAN2G(2412, 0), /* Channel 1 */ - CHAN2G(2417, 1), /* Channel 2 */ - CHAN2G(2422, 2), /* Channel 3 */ - CHAN2G(2427, 3), /* Channel 4 */ - CHAN2G(2432, 4), /* Channel 5 */ - CHAN2G(2437, 5), /* Channel 6 */ - CHAN2G(2442, 6), /* Channel 7 */ - CHAN2G(2447, 7), /* Channel 8 */ - CHAN2G(2452, 8), /* Channel 9 */ - CHAN2G(2457, 9), /* Channel 10 */ - CHAN2G(2462, 10), /* Channel 11 */ - CHAN2G(2467, 11), /* Channel 12 */ - CHAN2G(2472, 12), /* Channel 13 */ - CHAN2G(2484, 13), /* Channel 14 */ -}; +static int ath9k_ps_enable; +module_param_named(ps_enable, ath9k_ps_enable, int, 0444); +MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); -static struct ieee80211_channel ath9k_5ghz_channels[] = { - /* _We_ call this UNII 1 */ - CHAN5G(5180, 14), /* Channel 36 */ - CHAN5G(5200, 15), /* Channel 40 */ - CHAN5G(5220, 16), /* Channel 44 */ - CHAN5G(5240, 17), /* Channel 48 */ - /* _We_ call this UNII 2 */ - CHAN5G(5260, 18), /* Channel 52 */ - CHAN5G(5280, 19), /* Channel 56 */ - CHAN5G(5300, 20), /* Channel 60 */ - CHAN5G(5320, 21), /* Channel 64 */ - /* _We_ call this "Middle band" */ - CHAN5G(5500, 22), /* Channel 100 */ - CHAN5G(5520, 23), /* Channel 104 */ - CHAN5G(5540, 24), /* Channel 108 */ - CHAN5G(5560, 25), /* Channel 112 */ - CHAN5G(5580, 26), /* Channel 116 */ - CHAN5G(5600, 27), /* Channel 120 */ - CHAN5G(5620, 28), /* Channel 124 */ - CHAN5G(5640, 29), /* Channel 128 */ - CHAN5G(5660, 30), /* Channel 132 */ - CHAN5G(5680, 31), /* Channel 136 */ - CHAN5G(5700, 32), /* Channel 140 */ - /* _We_ call this UNII 3 */ - CHAN5G(5745, 33), /* Channel 149 */ - CHAN5G(5765, 34), /* Channel 153 */ - CHAN5G(5785, 35), /* Channel 157 */ - CHAN5G(5805, 36), /* Channel 161 */ - CHAN5G(5825, 37), /* Channel 165 */ -}; - -/* Atheros hardware rate code addition for short premble */ -#define SHPCHECK(__hw_rate, __flags) \ - ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0) - -#define RATE(_bitrate, _hw_rate, _flags) { \ - .bitrate = (_bitrate), \ - .flags = (_flags), \ - .hw_value = (_hw_rate), \ - .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ -} - -static struct ieee80211_rate ath9k_legacy_rates[] = { - RATE(10, 0x1b, 0), - RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */ - RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */ - RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */ - RATE(60, 0x0b, 0), - RATE(90, 0x0f, 0), - RATE(120, 0x0a, 0), - RATE(180, 0x0e, 0), - RATE(240, 0x09, 0), - RATE(360, 0x0d, 0), - RATE(480, 0x08, 0), - RATE(540, 0x0c, 0), -}; +int htc_use_dev_fw = 0; +module_param_named(use_dev_fw, htc_use_dev_fw, int, 0444); +MODULE_PARM_DESC(use_dev_fw, "Use development FW version"); #ifdef CONFIG_MAC80211_LEDS +int ath9k_htc_led_blink = 1; +module_param_named(blink, ath9k_htc_led_blink, int, 0444); +MODULE_PARM_DESC(blink, "Enable LED blink on activity"); + static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { { .throughput = 0 * 1024, .blink_time = 334 }, { .throughput = 1 * 1024, .blink_time = 260 }, @@ -136,9 +61,24 @@ static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { }; #endif +static void ath9k_htc_op_ps_wakeup(struct ath_common *common) +{ + ath9k_htc_ps_wakeup(common->priv); +} + +static void ath9k_htc_op_ps_restore(struct ath_common *common) +{ + ath9k_htc_ps_restore(common->priv); +} + +static const struct ath_ps_ops ath9k_htc_ps_ops = { + .wakeup = ath9k_htc_op_ps_wakeup, + .restore = ath9k_htc_op_ps_restore, +}; + static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) { - int time_left; + unsigned long time_left; if (atomic_read(&priv->htc->tgt_ready) > 0) { atomic_dec(&priv->htc->tgt_ready); @@ -170,6 +110,7 @@ static void ath9k_deinit_device(struct ath9k_htc_priv *priv) wiphy_rfkill_stop_polling(hw->wiphy); ath9k_deinit_leds(priv); + ath9k_htc_deinit_debug(priv); ieee80211_unregister_hw(hw); ath9k_rx_cleanup(priv); ath9k_tx_cleanup(priv); @@ -292,9 +233,9 @@ static void ath9k_reg_notifier(struct wiphy *wiphy, static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset) { - struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; __be32 val, reg = cpu_to_be32(reg_offset); int r; @@ -305,7 +246,7 @@ static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset) if (unlikely(r)) { ath_dbg(common, WMI, "REGISTER READ FAILED: (0x%04x, %d)\n", reg_offset, r); - return -EIO; + return -1; } return be32_to_cpu(val); @@ -314,18 +255,18 @@ static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset) static void ath9k_multi_regread(void *hw_priv, u32 *addr, u32 *val, u16 count) { - struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; __be32 tmpaddr[8]; __be32 tmpval[8]; int i, ret; - for (i = 0; i < count; i++) { - tmpaddr[i] = cpu_to_be32(addr[i]); - } + for (i = 0; i < count; i++) { + tmpaddr[i] = cpu_to_be32(addr[i]); + } - ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID, + ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID, (u8 *)tmpaddr , sizeof(u32) * count, (u8 *)tmpval, sizeof(u32) * count, 100); @@ -334,16 +275,35 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr, "Multiple REGISTER READ FAILED (count: %d)\n", count); } - for (i = 0; i < count; i++) { - val[i] = be32_to_cpu(tmpval[i]); - } + for (i = 0; i < count; i++) { + val[i] = be32_to_cpu(tmpval[i]); + } +} + +static void ath9k_regwrite_multi(struct ath_common *common) +{ + struct ath9k_htc_priv *priv = common->priv; + u32 rsp_status; + int r; + + r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, + (u8 *) &priv->wmi->multi_write, + sizeof(struct register_write) * priv->wmi->multi_write_idx, + (u8 *) &rsp_status, sizeof(rsp_status), + 100); + if (unlikely(r)) { + ath_dbg(common, WMI, + "REGISTER WRITE FAILED, multi len: %d\n", + priv->wmi->multi_write_idx); + } + priv->wmi->multi_write_idx = 0; } static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset) { - struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; const __be32 buf[2] = { cpu_to_be32(reg_offset), cpu_to_be32(val), @@ -362,11 +322,9 @@ static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset) static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) { - struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - u32 rsp_status; - int r; + struct ath9k_htc_priv *priv = common->priv; mutex_lock(&priv->wmi->multi_write_mutex); @@ -379,28 +337,17 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset) priv->wmi->multi_write_idx++; /* If the buffer is full, send it out. */ - if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) { - r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, - (u8 *) &priv->wmi->multi_write, - sizeof(struct register_write) * priv->wmi->multi_write_idx, - (u8 *) &rsp_status, sizeof(rsp_status), - 100); - if (unlikely(r)) { - ath_dbg(common, WMI, - "REGISTER WRITE FAILED, multi len: %d\n", - priv->wmi->multi_write_idx); - } - priv->wmi->multi_write_idx = 0; - } + if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) + ath9k_regwrite_multi(common); mutex_unlock(&priv->wmi->multi_write_mutex); } static void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset) { - struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; if (atomic_read(&priv->wmi->mwrite_cnt)) ath9k_regwrite_buffer(hw_priv, val, reg_offset); @@ -410,51 +357,158 @@ static void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset) static void ath9k_enable_regwrite_buffer(void *hw_priv) { - struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct ath9k_htc_priv *priv = common->priv; atomic_inc(&priv->wmi->mwrite_cnt); } static void ath9k_regwrite_flush(void *hw_priv) { - struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - u32 rsp_status; - int r; + struct ath9k_htc_priv *priv = common->priv; atomic_dec(&priv->wmi->mwrite_cnt); mutex_lock(&priv->wmi->multi_write_mutex); - if (priv->wmi->multi_write_idx) { - r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, - (u8 *) &priv->wmi->multi_write, - sizeof(struct register_write) * priv->wmi->multi_write_idx, + if (priv->wmi->multi_write_idx) + ath9k_regwrite_multi(common); + + mutex_unlock(&priv->wmi->multi_write_mutex); +} + +static void ath9k_reg_rmw_buffer(void *hw_priv, + u32 reg_offset, u32 set, u32 clr) +{ + struct ath_hw *ah = hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = common->priv; + u32 rsp_status; + int r; + + mutex_lock(&priv->wmi->multi_rmw_mutex); + + /* Store the register/value */ + priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].reg = + cpu_to_be32(reg_offset); + priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].set = + cpu_to_be32(set); + priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].clr = + cpu_to_be32(clr); + + priv->wmi->multi_rmw_idx++; + + /* If the buffer is full, send it out. */ + if (priv->wmi->multi_rmw_idx == MAX_RMW_CMD_NUMBER) { + r = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID, + (u8 *) &priv->wmi->multi_rmw, + sizeof(struct register_write) * priv->wmi->multi_rmw_idx, (u8 *) &rsp_status, sizeof(rsp_status), 100); if (unlikely(r)) { ath_dbg(common, WMI, - "REGISTER WRITE FAILED, multi len: %d\n", - priv->wmi->multi_write_idx); + "REGISTER RMW FAILED, multi len: %d\n", + priv->wmi->multi_rmw_idx); } - priv->wmi->multi_write_idx = 0; + priv->wmi->multi_rmw_idx = 0; } - mutex_unlock(&priv->wmi->multi_write_mutex); + mutex_unlock(&priv->wmi->multi_rmw_mutex); +} + +static void ath9k_reg_rmw_flush(void *hw_priv) +{ + struct ath_hw *ah = hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = common->priv; + u32 rsp_status; + int r; + + if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) + return; + + atomic_dec(&priv->wmi->m_rmw_cnt); + + mutex_lock(&priv->wmi->multi_rmw_mutex); + + if (priv->wmi->multi_rmw_idx) { + r = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID, + (u8 *) &priv->wmi->multi_rmw, + sizeof(struct register_rmw) * priv->wmi->multi_rmw_idx, + (u8 *) &rsp_status, sizeof(rsp_status), + 100); + if (unlikely(r)) { + ath_dbg(common, WMI, + "REGISTER RMW FAILED, multi len: %d\n", + priv->wmi->multi_rmw_idx); + } + priv->wmi->multi_rmw_idx = 0; + } + + mutex_unlock(&priv->wmi->multi_rmw_mutex); +} + +static void ath9k_enable_rmw_buffer(void *hw_priv) +{ + struct ath_hw *ah = hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = common->priv; + + if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) + return; + + atomic_inc(&priv->wmi->m_rmw_cnt); +} + +static void ath9k_reg_rmw_single(void *hw_priv, + u32 reg_offset, u32 set, u32 clr) +{ + struct ath_hw *ah = hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = common->priv; + struct register_rmw buf, buf_ret; + int ret; + + buf.reg = cpu_to_be32(reg_offset); + buf.set = cpu_to_be32(set); + buf.clr = cpu_to_be32(clr); + + ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID, + (u8 *) &buf, sizeof(buf), + (u8 *) &buf_ret, sizeof(buf_ret), + 100); + if (unlikely(ret)) { + ath_dbg(common, WMI, "REGISTER RMW FAILED:(0x%04x, %d)\n", + reg_offset, ret); + } } static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) { - u32 val; + struct ath_hw *ah = hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = common->priv; - val = ath9k_regread(hw_priv, reg_offset); - val &= ~clr; - val |= set; - ath9k_regwrite(hw_priv, val, reg_offset); - return val; + if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) { + u32 val; + + val = REG_READ(ah, reg_offset); + val &= ~clr; + val |= set; + REG_WRITE(ah, reg_offset, val); + + return 0; + } + + if (atomic_read(&priv->wmi->m_rmw_cnt)) + ath9k_reg_rmw_buffer(hw_priv, reg_offset, set, clr); + else + ath9k_reg_rmw_single(hw_priv, reg_offset, set, clr); + + return 0; } static void ath_usb_read_cachesize(struct ath_common *common, int *csz) @@ -464,18 +518,18 @@ static void ath_usb_read_cachesize(struct ath_common *common, int *csz) static bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data) { - struct ath_hw *ah = (struct ath_hw *) common->ah; + struct ath_hw *ah = common->ah; (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); if (!ath9k_hw_wait(ah, - AR_EEPROM_STATUS_DATA, + AR_EEPROM_STATUS_DATA(ah), AR_EEPROM_STATUS_DATA_BUSY | AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, AH_WAIT_TIMEOUT)) return false; - *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), + *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA(ah)), AR_EEPROM_STATUS_DATA_VAL); return true; @@ -487,51 +541,6 @@ static const struct ath_bus_ops ath9k_usb_bus_ops = { .eeprom_read = ath_usb_eeprom_read, }; -static void setup_ht_cap(struct ath9k_htc_priv *priv, - struct ieee80211_sta_ht_cap *ht_info) -{ - struct ath_common *common = ath9k_hw_common(priv->ah); - u8 tx_streams, rx_streams; - int i; - - ht_info->ht_supported = true; - ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_SM_PS | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_DSSSCCK40; - - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) - ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - - ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - - ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; - - memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - - /* ath9k_htc supports only 1 or 2 stream devices */ - tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2); - rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2); - - ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", - tx_streams, rx_streams); - - if (tx_streams >= 2) - ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; - - if (tx_streams != rx_streams) { - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; - ht_info->mcs.tx_params |= ((tx_streams - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); - } - - for (i = 0; i < rx_streams; i++) - ht_info->mcs.rx_mask[i] = 0xff; - - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; -} - static int ath9k_init_queues(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); @@ -540,8 +549,8 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv) for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++) priv->hwq_map[i] = -1; - priv->beaconq = ath9k_hw_beaconq_setup(priv->ah); - if (priv->beaconq == -1) { + priv->beacon.beaconq = ath9k_hw_beaconq_setup(priv->ah); + if (priv->beacon.beaconq == -1) { ath_err(common, "Unable to setup BEACON xmit queue\n"); goto err; } @@ -576,38 +585,22 @@ err: return -EINVAL; } -static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv) -{ - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { - priv->sbands[IEEE80211_BAND_2GHZ].channels = - ath9k_2ghz_channels; - priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - priv->sbands[IEEE80211_BAND_2GHZ].n_channels = - ARRAY_SIZE(ath9k_2ghz_channels); - priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; - priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates); - } - - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { - priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels; - priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; - priv->sbands[IEEE80211_BAND_5GHZ].n_channels = - ARRAY_SIZE(ath9k_5ghz_channels); - priv->sbands[IEEE80211_BAND_5GHZ].bitrates = - ath9k_legacy_rates + 4; - priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates) - 4; - } -} - static void ath9k_init_misc(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); - memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); + eth_broadcast_addr(common->bssidmask); + common->last_rssi = ATH_RSSI_DUMMY_MARKER; priv->ah->opmode = NL80211_IFTYPE_STATION; + + priv->spec_priv.ah = priv->ah; + priv->spec_priv.spec_config.enabled = 0; + priv->spec_priv.spec_config.short_repeat = true; + priv->spec_priv.spec_config.count = 8; + priv->spec_priv.spec_config.endless = false; + priv->spec_priv.spec_config.period = 0x12; + priv->spec_priv.spec_config.fft_period = 0x02; } static int ath9k_init_priv(struct ath9k_htc_priv *priv, @@ -618,12 +611,12 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, struct ath_common *common; int i, ret = 0, csz = 0; - set_bit(OP_INVALID, &priv->op_flags); - ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); if (!ah) return -ENOMEM; + ah->dev = priv->dev; + ah->hw = priv->hw; ah->hw_version.devid = devid; ah->hw_version.usbdev = drv_info; ah->ah_flags |= AH_USE_EEPROM; @@ -632,31 +625,32 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, ah->reg_ops.write = ath9k_regwrite; ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer; ah->reg_ops.write_flush = ath9k_regwrite_flush; + ah->reg_ops.enable_rmw_buffer = ath9k_enable_rmw_buffer; + ah->reg_ops.rmw_flush = ath9k_reg_rmw_flush; ah->reg_ops.rmw = ath9k_reg_rmw; priv->ah = ah; common = ath9k_hw_common(ah); common->ops = &ah->reg_ops; + common->ps_ops = &ath9k_htc_ps_ops; common->bus_ops = &ath9k_usb_bus_ops; common->ah = ah; common->hw = priv->hw; common->priv = priv; common->debug_mask = ath9k_debug; common->btcoex_enabled = ath9k_htc_btcoex_enable == 1; + set_bit(ATH_OP_INVALID, &common->op_flags); spin_lock_init(&priv->beacon_lock); spin_lock_init(&priv->tx.tx_lock); mutex_init(&priv->mutex); mutex_init(&priv->htc_pm_lock); - tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, - (unsigned long)priv); - tasklet_init(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet, - (unsigned long)priv); + tasklet_setup(&priv->rx_tasklet, ath9k_rx_tasklet); + tasklet_setup(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet); INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work); INIT_WORK(&priv->ps_work, ath9k_ps_work); INIT_WORK(&priv->fatal_work, ath9k_fatal_work); - setup_timer(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer, - (unsigned long)priv); + timer_setup(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer, 0); /* * Cache line size is used to size and align various @@ -678,10 +672,11 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, goto err_queues; for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) - priv->cur_beacon_conf.bslot[i] = NULL; + priv->beacon.bslot[i] = NULL; + priv->beacon.slottime = 9; + ath9k_cmn_init_channels_rates(common); ath9k_cmn_init_crypto(ah); - ath9k_init_channels_rates(priv); ath9k_init_misc(priv); ath9k_htc_init_btcoex(priv, product); @@ -717,19 +712,23 @@ static const struct ieee80211_iface_combination if_comb = { static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, struct ieee80211_hw *hw) { + struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(priv->ah); struct base_eep_header *pBase; - hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_AMPDU_AGGREGATION | - IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_HAS_RATE_CONTROL | - IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_PS_NULLFUNC_STACK | - IEEE80211_HW_REPORTS_TX_ACK_STATUS | - IEEE80211_HW_MFP_CAPABLE | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; + ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); + ieee80211_hw_set(hw, MFP_CAPABLE); + ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); + ieee80211_hw_set(hw, PS_NULLFUNC_STACK); + ieee80211_hw_set(hw, RX_INCLUDES_FCS); + ieee80211_hw_set(hw, HAS_RATE_CONTROL); + ieee80211_hw_set(hw, SPECTRUM_MGMT); + ieee80211_hw_set(hw, SIGNAL_DBM); + ieee80211_hw_set(hw, AMPDU_AGGREGATION); + ieee80211_hw_set(hw, DOESNT_SUPPORT_QOS_NDP); + + if (ath9k_ps_enable) + ieee80211_hw_set(hw, SUPPORTS_PS); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | @@ -737,7 +736,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_MESH_POINT); + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_OCB); hw->wiphy->iface_combinations = &if_comb; hw->wiphy->n_iface_combinations = 1; @@ -745,10 +745,12 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | + WIPHY_FLAG_HAS_CHANNEL_SWITCH; + + hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; hw->queues = 4; - hw->channel_change_time = 5000; hw->max_listen_interval = 1; hw->vif_data_size = sizeof(struct ath9k_htc_vif); @@ -759,20 +761,13 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, sizeof(struct htc_frame_hdr) + 4; if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &priv->sbands[IEEE80211_BAND_2GHZ]; + hw->wiphy->bands[NL80211_BAND_2GHZ] = + &common->sbands[NL80211_BAND_2GHZ]; if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &priv->sbands[IEEE80211_BAND_5GHZ]; - - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - setup_ht_cap(priv, - &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - setup_ht_cap(priv, - &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap); - } + hw->wiphy->bands[NL80211_BAND_5GHZ] = + &common->sbands[NL80211_BAND_5GHZ]; + + ath9k_cmn_reload_chainmask(ah); pBase = ath9k_htc_get_eeprom_base(priv); if (pBase) { @@ -781,6 +776,10 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, } SET_IEEE80211_PERM_ADDR(hw, common->macaddr); + + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + wiphy_ext_feature_set(hw->wiphy, + NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); } static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv) @@ -817,6 +816,12 @@ static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv) return -EINVAL; } + if (priv->fw_version_major == 1 && priv->fw_version_minor < 4) + set_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags); + + dev_info(priv->dev, "FW RMW support: %s\n", + test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags) ? "Off" : "On"); + return 0; } @@ -861,6 +866,7 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, if (error != 0) goto err_rx; + ath9k_hw_disable(priv->ah); #ifdef CONFIG_MAC80211_LEDS /* must be initialized before ieee80211_register_hw */ priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw, @@ -925,8 +931,9 @@ err_init: int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, u16 devid, char *product, u32 drv_info) { - struct ieee80211_hw *hw; + struct hif_device_usb *hif_dev; struct ath9k_htc_priv *priv; + struct ieee80211_hw *hw; int ret; hw = ieee80211_alloc_hw(sizeof(struct ath9k_htc_priv), &ath9k_htc_ops); @@ -937,7 +944,6 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, priv->hw = hw; priv->htc = htc_handle; priv->dev = dev; - htc_handle->drv_priv = priv; SET_IEEE80211_DEV(hw, priv->dev); ret = ath9k_htc_wait_for_target(priv); @@ -958,10 +964,19 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, if (ret) goto err_init; + htc_handle->drv_priv = priv; + + /* Allow ath9k_wmi_event_tasklet() to operate. */ + smp_wmb(); + priv->initialized = true; + return 0; err_init: - ath9k_deinit_wmi(priv); + ath9k_stop_wmi(priv); + hif_dev = htc_handle->hif_dev; + ath9k_hif_usb_dealloc_urbs(hif_dev); + ath9k_destroy_wmi(priv); err_free: ieee80211_free_hw(hw); return ret; @@ -976,7 +991,9 @@ void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug) htc_handle->drv_priv->ah->ah_flags |= AH_UNPLUGGED; ath9k_deinit_device(htc_handle->drv_priv); - ath9k_deinit_wmi(htc_handle->drv_priv); + ath9k_stop_wmi(htc_handle->drv_priv); + ath9k_hif_usb_dealloc_urbs(htc_handle->hif_dev); + ath9k_destroy_wmi(htc_handle->drv_priv); ieee80211_free_hw(htc_handle->drv_priv->hw); } } @@ -999,6 +1016,8 @@ int ath9k_htc_resume(struct htc_target *htc_handle) ret = ath9k_init_htc_services(priv, priv->ah->hw_version.devid, priv->ah->hw_version.usbdev); + ath9k_configure_leds(priv); + return ret; } #endif diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 5c1bec18c9e3..0d6272ac0dac 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -24,30 +24,10 @@ static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv, struct ath9k_channel *ichan) { - enum htc_phymode mode; - - mode = -EINVAL; + if (IS_CHAN_5GHZ(ichan)) + return HTC_MODE_11NA; - switch (ichan->chanmode) { - case CHANNEL_G: - case CHANNEL_G_HT20: - case CHANNEL_G_HT40PLUS: - case CHANNEL_G_HT40MINUS: - mode = HTC_MODE_11NG; - break; - case CHANNEL_A: - case CHANNEL_A_HT20: - case CHANNEL_A_HT40PLUS: - case CHANNEL_A_HT40MINUS: - mode = HTC_MODE_11NA; - break; - default: - break; - } - - WARN_ON(mode < 0); - - return mode; + return HTC_MODE_11NG; } bool ath9k_htc_setpower(struct ath9k_htc_priv *priv, @@ -115,10 +95,12 @@ static void ath9k_htc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) if ((vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_MESH_POINT) && - bss_conf->enable_beacon) + bss_conf->enable_beacon) { priv->reconfig_beacon = true; + priv->rearm_ani = true; + } - if (bss_conf->assoc) { + if (vif->cfg.assoc) { priv->rearm_ani = true; priv->reconfig_beacon = true; } @@ -147,22 +129,27 @@ static void ath9k_htc_bssid_iter(void *data, u8 *mac, struct ieee80211_vif *vif) struct ath9k_vif_iter_data *iter_data = data; int i; - for (i = 0; i < ETH_ALEN; i++) - iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]); + if (iter_data->hw_macaddr != NULL) { + for (i = 0; i < ETH_ALEN; i++) + iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]); + } else { + iter_data->hw_macaddr = mac; + } } -static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv, +static void ath9k_htc_set_mac_bssid_mask(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_vif_iter_data iter_data; /* - * Use the hardware MAC address as reference, the hardware uses it - * together with the BSSID mask when matching addresses. + * Pick the MAC address of the first interface as the new hardware + * MAC address. The hardware will use it together with the BSSID mask + * when matching addresses. */ - iter_data.hw_macaddr = common->macaddr; - memset(&iter_data.mask, 0xff, ETH_ALEN); + iter_data.hw_macaddr = NULL; + eth_broadcast_addr(iter_data.mask); if (vif) ath9k_htc_bssid_iter(&iter_data, vif->addr, vif); @@ -173,6 +160,10 @@ static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv, ath9k_htc_bssid_iter, &iter_data); memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); + + if (iter_data.hw_macaddr) + memcpy(common->macaddr, iter_data.hw_macaddr, ETH_ALEN); + ath_hw_setbssidmask(common); } @@ -207,7 +198,7 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) ath9k_htc_stop_ani(priv); ieee80211_stop_queues(priv->hw); - del_timer_sync(&priv->tx.cleanup_timer); + timer_delete_sync(&priv->tx.cleanup_timer); ath9k_htc_tx_drain(priv); WMI_CMD(WMI_DISABLE_INTR_CMDID); @@ -255,20 +246,21 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, struct ieee80211_conf *conf = &common->hw->conf; bool fastcc; struct ieee80211_channel *channel = hw->conf.chandef.chan; - struct ath9k_hw_cal_data *caldata = NULL; + struct ath9k_hw_cal_data *caldata; enum htc_phymode mode; __be16 htc_mode; u8 cmd_rsp; int ret; - if (test_bit(OP_INVALID, &priv->op_flags)) + if (test_bit(ATH_OP_INVALID, &common->op_flags)) return -EIO; fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); ath9k_htc_ps_wakeup(priv); - del_timer_sync(&priv->tx.cleanup_timer); + ath9k_htc_stop_ani(priv); + timer_delete_sync(&priv->tx.cleanup_timer); ath9k_htc_tx_drain(priv); WMI_CMD(WMI_DISABLE_INTR_CMDID); @@ -282,10 +274,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, priv->ah->curchan->channel, channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf), fastcc); - - if (!fastcc) - caldata = &priv->caldata; - + caldata = fastcc ? NULL : &priv->caldata; ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); if (ret) { ath_err(common, @@ -315,13 +304,17 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, htc_start(priv->htc); - if (!test_bit(OP_SCANNING, &priv->op_flags) && + if (!test_bit(ATH_OP_SCANNING, &common->op_flags) && !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) ath9k_htc_vif_reconfig(priv); mod_timer(&priv->tx.cleanup_timer, jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); + /* perform spectral scan if requested. */ + if (test_bit(ATH_OP_SCANNING, &common->op_flags) && + priv->spec_priv.spectral_mode == SPECTRAL_CHANSCAN) + ath9k_cmn_spectral_scan_trigger(common, &priv->spec_priv); err: ath9k_htc_ps_restore(priv); return ret; @@ -498,7 +491,7 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, ista->index = sta_idx; tsta.is_vif_sta = 0; maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + - sta->ht_cap.ampdu_factor); + sta->deflink.ht_cap.ampdu_factor); tsta.maxampdu = cpu_to_be16(maxampdu); } else { memcpy(&tsta.macaddr, vif->addr, ETH_ALEN); @@ -609,7 +602,7 @@ static void ath9k_htc_setup_rate(struct ath9k_htc_priv *priv, sband = priv->hw->wiphy->bands[priv->hw->conf.chandef.chan->band]; for (i = 0, j = 0; i < sband->n_bitrates; i++) { - if (sta->supp_rates[sband->band] & BIT(i)) { + if (sta->deflink.supp_rates[sband->band] & BIT(i)) { trate->rates.legacy_rates.rs_rates[j] = (sband->bitrates[i].bitrate * 2) / 10; j++; @@ -617,9 +610,9 @@ static void ath9k_htc_setup_rate(struct ath9k_htc_priv *priv, } trate->rates.legacy_rates.rs_nrates = j; - if (sta->ht_cap.ht_supported) { + if (sta->deflink.ht_cap.ht_supported) { for (i = 0, j = 0; i < 77; i++) { - if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) + if (sta->deflink.ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) trate->rates.ht_rates.rs_rates[j++] = i; if (j == ATH_HTC_RATE_MAX) break; @@ -627,18 +620,18 @@ static void ath9k_htc_setup_rate(struct ath9k_htc_priv *priv, trate->rates.ht_rates.rs_nrates = j; caps = WLAN_RC_HT_FLAG; - if (sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) + if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) caps |= ATH_RC_TX_STBC_FLAG; - if (sta->ht_cap.mcs.rx_mask[1]) + if (sta->deflink.ht_cap.mcs.rx_mask[1]) caps |= WLAN_RC_DS_FLAG; - if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && - (conf_is_ht40(&priv->hw->conf))) + if ((sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && + (conf_is_ht40(&priv->hw->conf))) caps |= WLAN_RC_40_FLAG; if (conf_is_ht40(&priv->hw->conf) && - (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) + (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) caps |= WLAN_RC_SGI_FLAG; else if (conf_is_ht20(&priv->hw->conf) && - (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)) + (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20)) caps |= WLAN_RC_SGI_FLAG; } @@ -726,7 +719,7 @@ static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv, aggr.sta_index = ista->index; aggr.tidno = tid & 0xf; - aggr.aggr_enable = (action == IEEE80211_AMPDU_TX_START) ? true : false; + aggr.aggr_enable = action == IEEE80211_AMPDU_TX_START; WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr); if (ret) @@ -759,7 +752,7 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv) common->ani.shortcal_timer = timestamp; common->ani.checkani_timer = timestamp; - set_bit(OP_ANI_RUNNING, &priv->op_flags); + set_bit(ATH_OP_ANI_RUN, &common->op_flags); ieee80211_queue_delayed_work(common->hw, &priv->ani_work, msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); @@ -767,8 +760,9 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv) void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv) { + struct ath_common *common = ath9k_hw_common(priv->ah); cancel_delayed_work_sync(&priv->ani_work); - clear_bit(OP_ANI_RUNNING, &priv->op_flags); + clear_bit(ATH_OP_ANI_RUN, &common->op_flags); } void ath9k_htc_ani_work(struct work_struct *work) @@ -797,8 +791,11 @@ void ath9k_htc_ani_work(struct work_struct *work) common->ani.longcal_timer = timestamp; } - /* Short calibration applies only while caldone is false */ - if (!common->ani.caldone) { + /* + * Short calibration applies only while caldone + * is false or -ETIMEDOUT + */ + if (common->ani.caldone <= 0) { if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) { shortcal = true; @@ -834,7 +831,7 @@ void ath9k_htc_ani_work(struct work_struct *work) if (longcal || shortcal) common->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan, - ah->rxchainmask, longcal); + ah->rxchainmask, longcal) > 0; ath9k_htc_ps_restore(priv); } @@ -847,7 +844,11 @@ set_timer: */ cal_interval = ATH_LONG_CALINTERVAL; cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); - if (!common->ani.caldone) + /* + * Short calibration applies only while caldone + * is false or -ETIMEDOUT + */ + if (common->ani.caldone <= 0) cal_interval = min(cal_interval, (u32)short_cal_interval); ieee80211_queue_delayed_work(common->hw, &priv->ani_work, @@ -926,7 +927,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) WMI_CMD(WMI_FLUSH_RECV_CMDID); /* setup initial channel */ - init_channel = ath9k_cmn_get_curchannel(hw, ah); + init_channel = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef); ret = ath9k_hw_reset(ah, init_channel, ah->caldata, false); if (ret) { @@ -953,7 +954,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) ath_dbg(common, CONFIG, "Failed to update capability in target\n"); - clear_bit(OP_INVALID, &priv->op_flags); + clear_bit(ATH_OP_INVALID, &common->op_flags); htc_start(priv->htc); spin_lock_bh(&priv->tx.tx_lock); @@ -972,7 +973,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) return ret; } -static void ath9k_htc_stop(struct ieee80211_hw *hw) +static void ath9k_htc_stop(struct ieee80211_hw *hw, bool suspend) { struct ath9k_htc_priv *priv = hw->priv; struct ath_hw *ah = priv->ah; @@ -982,7 +983,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); - if (test_bit(OP_INVALID, &priv->op_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); mutex_unlock(&priv->mutex); return; @@ -996,7 +997,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) tasklet_kill(&priv->rx_tasklet); - del_timer_sync(&priv->tx.cleanup_timer); + timer_delete_sync(&priv->tx.cleanup_timer); ath9k_htc_tx_drain(priv); ath9k_wmi_event_drain(priv); @@ -1024,7 +1025,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) ath9k_htc_ps_restore(priv); ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); - set_bit(OP_INVALID, &priv->op_flags); + set_bit(ATH_OP_INVALID, &common->op_flags); ath_dbg(common, CONFIG, "Driver halt\n"); mutex_unlock(&priv->mutex); @@ -1083,7 +1084,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, goto out; } - ath9k_htc_set_bssid_mask(priv, vif); + ath9k_htc_set_mac_bssid_mask(priv, vif); priv->vif_slot |= (1 << avp->index); priv->nvifs++; @@ -1098,7 +1099,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, ath9k_htc_set_opmode(priv); if ((priv->ah->opmode == NL80211_IFTYPE_AP) && - !test_bit(OP_ANI_RUNNING, &priv->op_flags)) { + !test_bit(ATH_OP_ANI_RUN, &common->op_flags)) { ath9k_hw_set_tsfadjust(priv->ah, true); ath9k_htc_start_ani(priv); } @@ -1137,6 +1138,9 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, priv->nvifs--; priv->vif_slot &= ~(1 << avp->index); + if (priv->csa_vif == vif) + priv->csa_vif = NULL; + ath9k_htc_remove_station(priv, vif, NULL); DEC_VIF(priv, vif->type); @@ -1148,7 +1152,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, ath9k_htc_set_opmode(priv); - ath9k_htc_set_bssid_mask(priv, vif); + ath9k_htc_set_mac_bssid_mask(priv, vif); /* * Stop ANI only if there are no associated station interfaces. @@ -1168,7 +1172,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); } -static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) +static int ath9k_htc_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct ath9k_htc_priv *priv = hw->priv; struct ath_common *common = ath9k_hw_common(priv->ah); @@ -1203,17 +1207,12 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || chip_reset) { struct ieee80211_channel *curchan = hw->conf.chandef.chan; - enum nl80211_channel_type channel_type = - cfg80211_get_chandef_type(&hw->conf.chandef); int pos = curchan->hw_value; ath_dbg(common, CONFIG, "Set channel: %d MHz\n", curchan->center_freq); - ath9k_cmn_update_ichannel(&priv->ah->channels[pos], - hw->conf.chandef.chan, - channel_type); - + ath9k_cmn_get_channel(hw, priv->ah, &hw->conf.chandef); if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) { ath_err(common, "Unable to set channel\n"); ret = -EINVAL; @@ -1246,13 +1245,13 @@ out: } #define SUPPORTED_FILTERS \ - (FIF_PROMISC_IN_BSS | \ - FIF_ALLMULTI | \ + (FIF_ALLMULTI | \ FIF_CONTROL | \ FIF_PSPOLL | \ FIF_OTHER_BSS | \ FIF_BCN_PRBRESP_PROMISC | \ FIF_PROBE_REQ | \ + FIF_MCAST_ACTION | \ FIF_FCSFAIL) static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, @@ -1261,13 +1260,13 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); u32 rfilt; mutex_lock(&priv->mutex); - changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; - if (test_bit(OP_INVALID, &priv->op_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(ath9k_hw_common(priv->ah), ANY, "Unable to configure filter on invalid state\n"); mutex_unlock(&priv->mutex); @@ -1286,18 +1285,50 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); } +static void ath9k_htc_sta_rc_update_work(struct work_struct *work) +{ + struct ath9k_htc_sta *ista = + container_of(work, struct ath9k_htc_sta, rc_update_work); + struct ieee80211_sta *sta = + container_of((void *)ista, struct ieee80211_sta, drv_priv); + struct ath9k_htc_priv *priv = ista->htc_priv; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_target_rate trate; + + mutex_lock(&priv->mutex); + ath9k_htc_ps_wakeup(priv); + + memset(&trate, 0, sizeof(struct ath9k_htc_target_rate)); + ath9k_htc_setup_rate(priv, sta, &trate); + if (!ath9k_htc_send_rate_cmd(priv, &trate)) + ath_dbg(common, CONFIG, + "Supported rates for sta: %pM updated, rate caps: 0x%X\n", + sta->addr, be32_to_cpu(trate.capflags)); + else + ath_dbg(common, CONFIG, + "Unable to update supported rates for sta: %pM\n", + sta->addr); + + ath9k_htc_ps_restore(priv); + mutex_unlock(&priv->mutex); +} + static int ath9k_htc_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct ath9k_htc_priv *priv = hw->priv; + struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; int ret; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); ret = ath9k_htc_add_station(priv, vif, sta); - if (!ret) + if (!ret) { + INIT_WORK(&ista->rc_update_work, ath9k_htc_sta_rc_update_work); + ista->htc_priv = priv; ath9k_htc_init_rate(priv, sta); + } ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); @@ -1309,12 +1340,13 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct ath9k_htc_priv *priv = hw->priv; - struct ath9k_htc_sta *ista; + struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; int ret; + cancel_work_sync(&ista->rc_update_work); + mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); - ista = (struct ath9k_htc_sta *) sta->drv_priv; htc_sta_drain(priv->htc, ista->index); ret = ath9k_htc_remove_station(priv, vif, sta); ath9k_htc_ps_restore(priv); @@ -1325,34 +1357,21 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, static void ath9k_htc_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u32 changed) + struct ieee80211_link_sta *link_sta, + u32 changed) { - struct ath9k_htc_priv *priv = hw->priv; - struct ath_common *common = ath9k_hw_common(priv->ah); - struct ath9k_htc_target_rate trate; - - mutex_lock(&priv->mutex); - ath9k_htc_ps_wakeup(priv); + struct ieee80211_sta *sta = link_sta->sta; + struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; - if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { - memset(&trate, 0, sizeof(struct ath9k_htc_target_rate)); - ath9k_htc_setup_rate(priv, sta, &trate); - if (!ath9k_htc_send_rate_cmd(priv, &trate)) - ath_dbg(common, CONFIG, - "Supported rates for sta: %pM updated, rate caps: 0x%X\n", - sta->addr, be32_to_cpu(trate.capflags)); - else - ath_dbg(common, CONFIG, - "Unable to update supported rates for sta: %pM\n", - sta->addr); - } + if (!(changed & IEEE80211_RC_SUPP_RATES_CHANGED)) + return; - ath9k_htc_ps_restore(priv); - mutex_unlock(&priv->mutex); + schedule_work(&ista->rc_update_work); } static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath9k_htc_priv *priv = hw->priv; @@ -1437,14 +1456,14 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw, key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; if (key->cipher == WLAN_CIPHER_SUITE_TKIP) key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - if (priv->ah->sw_mgmt_crypto && + if (priv->ah->sw_mgmt_crypto_tx && key->cipher == WLAN_CIPHER_SUITE_CCMP) key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; ret = 0; } break; case DISABLE_KEY: - ath_key_delete(common, key); + ath_key_delete(common, key->hw_key_idx); break; default: ret = -EINVAL; @@ -1467,13 +1486,15 @@ static void ath9k_htc_set_bssid(struct ath9k_htc_priv *priv) static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; + struct ath9k_htc_priv *priv = data; struct ath_common *common = ath9k_hw_common(priv->ah); struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - if ((vif->type == NL80211_IFTYPE_STATION) && bss_conf->assoc) { - common->curaid = bss_conf->aid; + if ((vif->type == NL80211_IFTYPE_STATION) && vif->cfg.assoc) { + common->curaid = vif->cfg.aid; + common->last_rssi = ATH_RSSI_DUMMY_MARKER; memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); } } @@ -1490,25 +1511,29 @@ static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv) static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { struct ath9k_htc_priv *priv = hw->priv; struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); + int slottime; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); if (changed & BSS_CHANGED_ASSOC) { ath_dbg(common, CONFIG, "BSS Changed ASSOC %d\n", - bss_conf->assoc); + vif->cfg.assoc); - bss_conf->assoc ? + vif->cfg.assoc ? priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--; + if (!vif->cfg.assoc) + clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); + if (priv->ah->opmode == NL80211_IFTYPE_STATION) { ath9k_htc_choose_set_bssid(priv); - if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1)) + if (vif->cfg.assoc && (priv->num_sta_assoc_vif == 1)) ath9k_htc_start_ani(priv); else if (priv->num_sta_assoc_vif == 0) ath9k_htc_stop_ani(priv); @@ -1517,7 +1542,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_IBSS) { if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) { - common->curaid = bss_conf->aid; + common->curaid = vif->cfg.aid; memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); ath9k_htc_set_bssid(priv); } @@ -1527,7 +1552,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ath_dbg(common, CONFIG, "Beacon enabled for BSS: %pM\n", bss_conf->bssid); ath9k_htc_set_tsfadjust(priv, vif); - set_bit(OP_ENABLE_BEACON, &priv->op_flags); + priv->cur_beacon_conf.enable_beacon = 1; ath9k_htc_beacon_config(priv, vif); } @@ -1541,7 +1566,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ath_dbg(common, CONFIG, "Beacon disabled for BSS: %pM\n", bss_conf->bssid); - clear_bit(OP_ENABLE_BEACON, &priv->op_flags); + priv->cur_beacon_conf.enable_beacon = 0; ath9k_htc_beacon_config(priv, vif); } } @@ -1567,11 +1592,21 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ERP_SLOT) { if (bss_conf->use_short_slot) - ah->slottime = 9; + slottime = 9; else - ah->slottime = 20; - - ath9k_hw_init_global_settings(ah); + slottime = 20; + if (vif->type == NL80211_IFTYPE_AP) { + /* + * Defer update, so that connected stations can adjust + * their settings at the same time. + * See beacon.c for more details + */ + priv->beacon.slottime = slottime; + priv->beacon.updateslot = UPDATE; + } else { + ah->slottime = slottime; + ath9k_hw_init_global_settings(ah); + } } if (changed & BSS_CHANGED_HT) @@ -1622,13 +1657,14 @@ static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw, static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, - u16 tid, u16 *ssn, u8 buf_size) + struct ieee80211_ampdu_params *params) { struct ath9k_htc_priv *priv = hw->priv; struct ath9k_htc_sta *ista; int ret = 0; + struct ieee80211_sta *sta = params->sta; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; mutex_lock(&priv->mutex); ath9k_htc_ps_wakeup(priv); @@ -1641,7 +1677,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_START: ret = ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid); if (!ret) - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: @@ -1650,6 +1686,10 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: + if (tid >= ATH9K_HTC_MAX_TID) { + ret = -EINVAL; + break; + } ista = (struct ath9k_htc_sta *) sta->drv_priv; spin_lock_bh(&priv->tx.tx_lock); ista->tid_state[tid] = AGGR_OPERATIONAL; @@ -1665,26 +1705,31 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, return ret; } -static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) +static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *mac_addr) { struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); mutex_lock(&priv->mutex); spin_lock_bh(&priv->beacon_lock); - set_bit(OP_SCANNING, &priv->op_flags); + set_bit(ATH_OP_SCANNING, &common->op_flags); spin_unlock_bh(&priv->beacon_lock); cancel_work_sync(&priv->ps_work); ath9k_htc_stop_ani(priv); mutex_unlock(&priv->mutex); } -static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) +static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); mutex_lock(&priv->mutex); spin_lock_bh(&priv->beacon_lock); - clear_bit(OP_SCANNING, &priv->op_flags); + clear_bit(ATH_OP_SCANNING, &common->op_flags); spin_unlock_bh(&priv->beacon_lock); ath9k_htc_ps_wakeup(priv); ath9k_htc_vif_reconfig(priv); @@ -1692,13 +1737,15 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); } -static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, + int radio_idx, u32 value) { return 0; } static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw, - u8 coverage_class) + int radio_idx, + s16 coverage_class) { struct ath9k_htc_priv *priv = hw->priv; @@ -1729,8 +1776,8 @@ static int ath9k_htc_set_bitrate_mask(struct ieee80211_hw *hw, memset(&tmask, 0, sizeof(struct ath9k_htc_target_rate_mask)); tmask.vif_index = avp->index; - tmask.band = IEEE80211_BAND_2GHZ; - tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_2GHZ].legacy); + tmask.band = NL80211_BAND_2GHZ; + tmask.mask = cpu_to_be32(mask->control[NL80211_BAND_2GHZ].legacy); WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask); if (ret) { @@ -1740,8 +1787,8 @@ static int ath9k_htc_set_bitrate_mask(struct ieee80211_hw *hw, goto out; } - tmask.band = IEEE80211_BAND_5GHZ; - tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_5GHZ].legacy); + tmask.band = NL80211_BAND_5GHZ; + tmask.mask = cpu_to_be32(mask->control[NL80211_BAND_5GHZ].legacy); WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask); if (ret) { @@ -1752,8 +1799,8 @@ static int ath9k_htc_set_bitrate_mask(struct ieee80211_hw *hw, } ath_dbg(common, CONFIG, "Set bitrate masks: 0x%x, 0x%x\n", - mask->control[IEEE80211_BAND_2GHZ].legacy, - mask->control[IEEE80211_BAND_5GHZ].legacy); + mask->control[NL80211_BAND_2GHZ].legacy, + mask->control[NL80211_BAND_5GHZ].legacy); out: return ret; } @@ -1796,8 +1843,8 @@ struct base_eep_header *ath9k_htc_get_eeprom_base(struct ath9k_htc_priv *priv) } -static int ath9k_htc_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, - u32 *rx_ant) +static int ath9k_htc_get_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 *tx_ant, u32 *rx_ant) { struct ath9k_htc_priv *priv = hw->priv; struct base_eep_header *pBase = ath9k_htc_get_eeprom_base(priv); @@ -1811,8 +1858,26 @@ static int ath9k_htc_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, return 0; } +static void ath9k_htc_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + struct ath9k_htc_priv *priv = hw->priv; + + /* mac80211 does not support CSA in multi-if cases (yet) */ + if (WARN_ON(priv->csa_vif)) + return; + + priv->csa_vif = vif; +} + struct ieee80211_ops ath9k_htc_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = ath9k_htc_tx, + .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = ath9k_htc_start, .stop = ath9k_htc_stop, .add_interface = ath9k_htc_add_interface, @@ -1822,7 +1887,7 @@ struct ieee80211_ops ath9k_htc_ops = { .sta_add = ath9k_htc_sta_add, .sta_remove = ath9k_htc_sta_remove, .conf_tx = ath9k_htc_conf_tx, - .sta_rc_update = ath9k_htc_sta_rc_update, + .link_sta_rc_update = ath9k_htc_sta_rc_update, .bss_info_changed = ath9k_htc_bss_info_changed, .set_key = ath9k_htc_set_key, .get_tsf = ath9k_htc_get_tsf, @@ -1837,6 +1902,7 @@ struct ieee80211_ops ath9k_htc_ops = { .set_bitrate_mask = ath9k_htc_set_bitrate_mask, .get_stats = ath9k_htc_get_stats, .get_antenna = ath9k_htc_get_antenna, + .channel_switch_beacon = ath9k_htc_channel_switch_beacon, #ifdef CONFIG_ATH9K_HTC_DEBUGFS .get_et_sset_count = ath9k_htc_get_et_sset_count, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index e602c9519709..ee5945cfc10e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -106,20 +106,20 @@ static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, switch (qnum) { case 0: - TX_QSTAT_INC(IEEE80211_AC_VO); + TX_QSTAT_INC(priv, IEEE80211_AC_VO); epid = priv->data_vo_ep; break; case 1: - TX_QSTAT_INC(IEEE80211_AC_VI); + TX_QSTAT_INC(priv, IEEE80211_AC_VI); epid = priv->data_vi_ep; break; case 2: - TX_QSTAT_INC(IEEE80211_AC_BE); + TX_QSTAT_INC(priv, IEEE80211_AC_BE); epid = priv->data_be_ep; break; case 3: default: - TX_QSTAT_INC(IEEE80211_AC_BK); + TX_QSTAT_INC(priv, IEEE80211_AC_BK); epid = priv->data_bk_ep; break; } @@ -297,7 +297,12 @@ static void ath9k_htc_tx_data(struct ath9k_htc_priv *priv, tx_hdr.data_type = ATH9K_HTC_NORMAL; } - if (ieee80211_is_data_qos(hdr->frame_control)) { + /* Transmit all frames that should not be reordered relative + * to each other using the same priority. For other QoS data + * frames extract the priority from the header. + */ + if (!(tx_info->control.flags & IEEE80211_TX_CTRL_DONT_REORDER) && + ieee80211_is_data_qos(hdr->frame_control)) { qc = ieee80211_get_qos_ctl(hdr); tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; } @@ -323,7 +328,7 @@ static void ath9k_htc_tx_data(struct ath9k_htc_priv *priv, memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); if (is_cab) { - CAB_STAT_INC; + CAB_STAT_INC(priv); tx_ctl->epid = priv->cab_ep; return; } @@ -448,6 +453,7 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, struct ieee80211_conf *cur_conf = &priv->hw->conf; bool txok; int slot; + int hdrlen, padsize; slot = strip_drv_header(priv, skb); if (slot < 0) { @@ -470,8 +476,11 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, if (!txok || !vif || !txs) goto send_mac80211; - if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) + if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) { tx_info->flags |= IEEE80211_TX_STAT_ACK; + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) + tx_info->flags |= IEEE80211_TX_STAT_AMPDU; + } if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT) tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; @@ -490,7 +499,7 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, if (txs->ts_flags & ATH9K_HTC_TXSTAT_SGI) rate->flags |= IEEE80211_TX_RC_SHORT_GI; } else { - if (cur_conf->chandef.chan->band == IEEE80211_BAND_5GHZ) + if (cur_conf->chandef.chan->band == NL80211_BAND_5GHZ) rate->idx += 4; /* No CCK rates */ } @@ -504,8 +513,17 @@ send_mac80211: ath9k_htc_tx_clear_slot(priv, slot); + /* Remove padding before handing frame back to mac80211 */ + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + + padsize = hdrlen & 3; + if (padsize && skb->len > hdrlen + padsize) { + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); + } + /* Send status to mac80211 */ - ieee80211_tx_status(priv->hw, skb); + ieee80211_tx_status_skb(priv->hw, skb); } static inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv, @@ -557,16 +575,16 @@ void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) spin_unlock_bh(&priv->tx.tx_lock); } -void ath9k_tx_failed_tasklet(unsigned long data) +void ath9k_tx_failed_tasklet(struct tasklet_struct *t) { - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; + struct ath9k_htc_priv *priv = from_tasklet(priv, t, tx_failed_tasklet); - spin_lock_bh(&priv->tx.tx_lock); + spin_lock(&priv->tx.tx_lock); if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { - spin_unlock_bh(&priv->tx.tx_lock); + spin_unlock(&priv->tx.tx_lock); return; } - spin_unlock_bh(&priv->tx.tx_lock); + spin_unlock(&priv->tx.tx_lock); ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); } @@ -628,15 +646,16 @@ static struct sk_buff* ath9k_htc_tx_get_packet(struct ath9k_htc_priv *priv, void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event) { - struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event; + struct wmi_event_txstatus *txs = wmi_event; struct __wmi_event_txstatus *__txs; struct sk_buff *skb; struct ath9k_htc_tx_event *tx_pend; int i; - for (i = 0; i < txs->cnt; i++) { - WARN_ON(txs->cnt > HTC_MAX_TX_STATUS); + if (WARN_ON_ONCE(txs->cnt > HTC_MAX_TX_STATUS)) + return; + for (i = 0; i < txs->cnt; i++) { __txs = &txs->txstatus[i]; skb = ath9k_htc_tx_get_packet(priv, __txs); @@ -671,7 +690,7 @@ void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event) void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, enum htc_endpoint_id ep_id, bool txok) { - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; + struct ath9k_htc_priv *priv = drv_priv; struct ath9k_htc_tx_ctl *tx_ctl; struct sk_buff_head *epid_queue; @@ -739,9 +758,10 @@ static void ath9k_htc_tx_cleanup_queue(struct ath9k_htc_priv *priv, } } -void ath9k_htc_tx_cleanup_timer(unsigned long data) +void ath9k_htc_tx_cleanup_timer(struct timer_list *t) { - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) data; + struct ath9k_htc_priv *priv = timer_container_of(priv, t, + tx.cleanup_timer); struct ath_common *common = ath9k_hw_common(priv->ah); struct ath9k_htc_tx_event *event, *tmp; struct sk_buff *skb; @@ -795,6 +815,7 @@ int ath9k_tx_init(struct ath9k_htc_priv *priv) skb_queue_head_init(&priv->tx.data_vi_queue); skb_queue_head_init(&priv->tx.data_vo_queue); skb_queue_head_init(&priv->tx.tx_failed); + return 0; } @@ -859,14 +880,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) if (priv->rxfilter & FIF_PROBE_REQ) rfilt |= ATH9K_RX_FILTER_PROBEREQ; - /* - * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station - * mode interface or when in monitor mode. AP mode does not need this - * since it receives all in-BSS frames anyway. - */ - if (((ah->opmode != NL80211_IFTYPE_AP) && - (priv->rxfilter & FIF_PROMISC_IN_BSS)) || - ah->is_monitoring) + if (ah->is_monitoring) rfilt |= ATH9K_RX_FILTER_PROM; if (priv->rxfilter & FIF_CONTROL) @@ -887,7 +901,8 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) if (priv->rxfilter & FIF_PSPOLL) rfilt |= ATH9K_RX_FILTER_PSPOLL; - if (priv->nvifs > 1 || priv->rxfilter & FIF_OTHER_BSS) + if (priv->nvifs > 1 || + priv->rxfilter & (FIF_OTHER_BSS | FIF_MCAST_ACTION)) rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; return rfilt; @@ -914,46 +929,44 @@ static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv) void ath9k_host_rx_init(struct ath9k_htc_priv *priv) { + struct ath_common *common = ath9k_hw_common(priv->ah); ath9k_hw_rxena(priv->ah); ath9k_htc_opmode_init(priv); - ath9k_hw_startpcureceive(priv->ah, test_bit(OP_SCANNING, &priv->op_flags)); - priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER; + ath9k_hw_startpcureceive(priv->ah, test_bit(ATH_OP_SCANNING, &common->op_flags)); } -static void ath9k_process_rate(struct ieee80211_hw *hw, - struct ieee80211_rx_status *rxs, - u8 rx_rate, u8 rs_flags) +static inline void convert_htc_flag(struct ath_rx_status *rx_stats, + struct ath_htc_rx_status *rxstatus) { - struct ieee80211_supported_band *sband; - enum ieee80211_band band; - unsigned int i = 0; - - if (rx_rate & 0x80) { - /* HT rate */ - rxs->flag |= RX_FLAG_HT; - if (rs_flags & ATH9K_RX_2040) - rxs->flag |= RX_FLAG_40MHZ; - if (rs_flags & ATH9K_RX_GI) - rxs->flag |= RX_FLAG_SHORT_GI; - rxs->rate_idx = rx_rate & 0x7f; - return; - } - - band = hw->conf.chandef.chan->band; - sband = hw->wiphy->bands[band]; - - for (i = 0; i < sband->n_bitrates; i++) { - if (sband->bitrates[i].hw_value == rx_rate) { - rxs->rate_idx = i; - return; - } - if (sband->bitrates[i].hw_value_short == rx_rate) { - rxs->rate_idx = i; - rxs->flag |= RX_FLAG_SHORTPRE; - return; - } - } + rx_stats->enc_flags = 0; + rx_stats->bw = RATE_INFO_BW_20; + if (rxstatus->rs_flags & ATH9K_RX_2040) + rx_stats->bw = RATE_INFO_BW_40; + if (rxstatus->rs_flags & ATH9K_RX_GI) + rx_stats->enc_flags |= RX_ENC_FLAG_SHORT_GI; +} +static void rx_status_htc_to_ath(struct ath_rx_status *rx_stats, + struct ath_htc_rx_status *rxstatus) +{ + rx_stats->rs_datalen = be16_to_cpu(rxstatus->rs_datalen); + rx_stats->rs_status = rxstatus->rs_status; + rx_stats->rs_phyerr = rxstatus->rs_phyerr; + rx_stats->rs_rssi = rxstatus->rs_rssi; + rx_stats->rs_keyix = rxstatus->rs_keyix; + rx_stats->rs_rate = rxstatus->rs_rate; + rx_stats->rs_antenna = rxstatus->rs_antenna; + rx_stats->rs_more = rxstatus->rs_more; + + memcpy(rx_stats->rs_rssi_ctl, rxstatus->rs_rssi_ctl, + sizeof(rx_stats->rs_rssi_ctl)); + memcpy(rx_stats->rs_rssi_ext, rxstatus->rs_rssi_ext, + sizeof(rx_stats->rs_rssi_ext)); + + rx_stats->rs_isaggr = rxstatus->rs_isaggr; + rx_stats->rs_moreaggr = rxstatus->rs_moreaggr; + rx_stats->rs_num_delims = rxstatus->rs_num_delims; + convert_htc_flag(rx_stats, rxstatus); } static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, @@ -965,10 +978,12 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, struct ieee80211_hw *hw = priv->hw; struct sk_buff *skb = rxbuf->skb; struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath_hw *ah = common->ah; struct ath_htc_rx_status *rxstatus; - int hdrlen, padsize; - int last_rssi = ATH_RSSI_DUMMY_MARKER; - __le16 fc; + struct ath_rx_status rx_stats; + bool decrypt_error = false; + u16 rs_datalen; + bool is_phyerr; if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { ath_err(common, "Corrupted RX frame, dropping (len: %d)\n", @@ -978,116 +993,84 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, rxstatus = (struct ath_htc_rx_status *)skb->data; - if (be16_to_cpu(rxstatus->rs_datalen) - - (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) { + rs_datalen = be16_to_cpu(rxstatus->rs_datalen); + if (unlikely(rs_datalen - + (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0)) { ath_err(common, "Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n", - rxstatus->rs_datalen, skb->len); + rs_datalen, skb->len); goto rx_next; } - ath9k_htc_err_stat_rx(priv, rxstatus); - - /* Get the RX status information */ - memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); - skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - hdrlen = ieee80211_get_hdrlen_from_skb(skb); + is_phyerr = rxstatus->rs_status & ATH9K_RXERR_PHY; + /* + * Discard zero-length packets and packets smaller than an ACK + * which are not PHY_ERROR (short radar pulses have a length of 3) + */ + if (unlikely(!rs_datalen || (rs_datalen < 10 && !is_phyerr))) { + ath_dbg(common, ANY, + "Short RX data len, dropping (dlen: %d)\n", + rs_datalen); + goto rx_next; + } - padsize = hdrlen & 3; - if (padsize && skb->len >= hdrlen+padsize+FCS_LEN) { - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); + if (rxstatus->rs_keyix >= ATH_KEYMAX && + rxstatus->rs_keyix != ATH9K_RXKEYIX_INVALID) { + ath_dbg(common, ANY, + "Invalid keyix, dropping (keyix: %d)\n", + rxstatus->rs_keyix); + goto rx_next; } + /* Get the RX status information */ + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - if (rxbuf->rxstatus.rs_status != 0) { - if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY) - goto rx_next; - - if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) { - /* FIXME */ - } else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) { - if (ieee80211_is_ctl(fc)) - /* - * Sometimes, we get invalid - * MIC failures on valid control frames. - * Remove these mic errors. - */ - rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC; - else - rx_status->flag |= RX_FLAG_MMIC_ERROR; - } + /* Copy everything from ath_htc_rx_status (HTC_RX_FRAME_HEADER). + * After this, we can drop this part of skb. */ + rx_status_htc_to_ath(&rx_stats, rxstatus); + ath9k_htc_err_stat_rx(priv, &rx_stats); + rx_status->mactime = be64_to_cpu(rxstatus->rs_tstamp); + skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); - /* - * Reject error frames with the exception of - * decryption and MIC failures. For monitor mode, - * we also ignore the CRC error. - */ - if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) { - if (rxbuf->rxstatus.rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | - ATH9K_RXERR_CRC)) - goto rx_next; - } else { - if (rxbuf->rxstatus.rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { - goto rx_next; - } - } - } + /* + * everything but the rate is checked here, the rate check is done + * separately to avoid doing two lookups for a rate for each frame. + */ + hdr = (struct ieee80211_hdr *)skb->data; - if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) { - u8 keyix; - keyix = rxbuf->rxstatus.rs_keyix; - if (keyix != ATH9K_RXKEYIX_INVALID) { - rx_status->flag |= RX_FLAG_DECRYPTED; - } else if (ieee80211_has_protected(fc) && - skb->len >= hdrlen + 4) { - keyix = skb->data[hdrlen + 3] >> 6; - if (test_bit(keyix, common->keymap)) - rx_status->flag |= RX_FLAG_DECRYPTED; + /* + * Process PHY errors and return so that the packet + * can be dropped. + */ + if (unlikely(is_phyerr)) { + /* TODO: Not using DFS processing now. */ + if (ath_cmn_process_fft(&priv->spec_priv, hdr, + &rx_stats, rx_status->mactime)) { + /* TODO: Code to collect spectral scan statistics */ } + goto rx_next; } - ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate, - rxbuf->rxstatus.rs_flags); - - if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD && - !rxbuf->rxstatus.rs_moreaggr) - ATH_RSSI_LPF(priv->rx.last_rssi, - rxbuf->rxstatus.rs_rssi); - - last_rssi = priv->rx.last_rssi; - - if (ieee80211_is_beacon(hdr->frame_control) && - !is_zero_ether_addr(common->curbssid) && - ether_addr_equal(hdr->addr3, common->curbssid)) { - s8 rssi = rxbuf->rxstatus.rs_rssi; + if (!ath9k_cmn_rx_accept(common, hdr, rx_status, &rx_stats, + &decrypt_error, priv->rxfilter)) + goto rx_next; - if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) - rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); + ath9k_cmn_rx_skb_postprocess(common, skb, &rx_stats, + rx_status, decrypt_error); - if (rssi < 0) - rssi = 0; + if (ath9k_cmn_process_rate(common, hw, &rx_stats, rx_status)) + goto rx_next; - priv->ah->stats.avgbrssi = rssi; - } + rx_stats.is_mybeacon = ath_is_mybeacon(common, hdr); + ath9k_cmn_process_rssi(common, hw, &rx_stats, rx_status); - rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp); - rx_status->band = hw->conf.chandef.chan->band; - rx_status->freq = hw->conf.chandef.chan->center_freq; - rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; - rx_status->antenna = rxbuf->rxstatus.rs_antenna; + rx_status->band = ah->curchan->chan->band; + rx_status->freq = ah->curchan->chan->center_freq; + rx_status->antenna = rx_stats.rs_antenna; rx_status->flag |= RX_FLAG_MACTIME_END; return true; - rx_next: return false; } @@ -1095,9 +1078,9 @@ rx_next: /* * FIXME: Handle FLUSH later on. */ -void ath9k_rx_tasklet(unsigned long data) +void ath9k_rx_tasklet(struct tasklet_struct *t) { - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; + struct ath9k_htc_priv *priv = from_tasklet(priv, t, rx_tasklet); struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; struct ieee80211_rx_status rx_status; struct sk_buff *skb; @@ -1152,29 +1135,34 @@ requeue: void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb, enum htc_endpoint_id ep_id) { - struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)drv_priv; + struct ath9k_htc_priv *priv = drv_priv; struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; + unsigned long flags; + + /* Check if ath9k_rx_init() completed. */ + if (!data_race(priv->rx.initialized)) + goto err; - spin_lock(&priv->rx.rxbuflock); + spin_lock_irqsave(&priv->rx.rxbuflock, flags); list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { if (!tmp_buf->in_process) { rxbuf = tmp_buf; break; } } - spin_unlock(&priv->rx.rxbuflock); + spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); if (rxbuf == NULL) { ath_dbg(common, ANY, "No free RX buffer\n"); goto err; } - spin_lock(&priv->rx.rxbuflock); + spin_lock_irqsave(&priv->rx.rxbuflock, flags); rxbuf->skb = skb; rxbuf->in_process = true; - spin_unlock(&priv->rx.rxbuflock); + spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); tasklet_schedule(&priv->rx_tasklet); return; @@ -1212,6 +1200,10 @@ int ath9k_rx_init(struct ath9k_htc_priv *priv) list_add_tail(&rxbuf->list, &priv->rx.rxbuf); } + /* Allow ath9k_htc_rxep() to operate. */ + smp_wmb(); + priv->rx.initialized = true; + return 0; err: diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index aac4a406a513..b5257b2b4aa5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -26,11 +26,11 @@ static int htc_issue_send(struct htc_target *target, struct sk_buff* skb, struct htc_endpoint *endpoint = &target->endpoint[epid]; int status; - hdr = (struct htc_frame_hdr *) - skb_push(skb, sizeof(struct htc_frame_hdr)); + hdr = skb_push(skb, sizeof(struct htc_frame_hdr)); hdr->endpoint_id = epid; hdr->flags = flags; hdr->payload_len = cpu_to_be16(len); + memset(hdr->control, 0, sizeof(hdr->control)); status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb); @@ -89,7 +89,7 @@ static void htc_process_target_rdy(struct htc_target *target, void *buf) { struct htc_endpoint *endpoint; - struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf; + struct htc_ready_msg *htc_ready_msg = buf; target->credit_size = be16_to_cpu(htc_ready_msg->credit_size); @@ -114,6 +114,15 @@ static void htc_process_conn_rsp(struct htc_target *target, if (svc_rspmsg->status == HTC_SERVICE_SUCCESS) { epid = svc_rspmsg->endpoint_id; + + /* Check that the received epid for the endpoint to attach + * a new service is valid. ENDPOINT0 can't be used here as it + * is already reserved for HTC_CTRL_RSVD_SVC service and thus + * should not be modified. + */ + if (epid <= ENDPOINT0 || epid >= ENDPOINT_MAX) + return; + service_id = be16_to_cpu(svc_rspmsg->service_id); max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len); endpoint = &target->endpoint[epid]; @@ -146,7 +155,8 @@ static int htc_config_pipe_credits(struct htc_target *target) { struct sk_buff *skb; struct htc_config_pipe_msg *cp_msg; - int ret, time_left; + int ret; + unsigned long time_left; skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC); if (!skb) { @@ -155,8 +165,7 @@ static int htc_config_pipe_credits(struct htc_target *target) } skb_reserve(skb, sizeof(struct htc_frame_hdr)); - cp_msg = (struct htc_config_pipe_msg *) - skb_put(skb, sizeof(struct htc_config_pipe_msg)); + cp_msg = skb_put(skb, sizeof(struct htc_config_pipe_msg)); cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID); cp_msg->pipe_id = USB_WLAN_TX_PIPE; @@ -184,7 +193,8 @@ static int htc_setup_complete(struct htc_target *target) { struct sk_buff *skb; struct htc_comp_msg *comp_msg; - int ret = 0, time_left; + int ret = 0; + unsigned long time_left; skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC); if (!skb) { @@ -193,8 +203,7 @@ static int htc_setup_complete(struct htc_target *target) } skb_reserve(skb, sizeof(struct htc_frame_hdr)); - comp_msg = (struct htc_comp_msg *) - skb_put(skb, sizeof(struct htc_comp_msg)); + comp_msg = skb_put(skb, sizeof(struct htc_comp_msg)); comp_msg->msg_id = cpu_to_be16(HTC_MSG_SETUP_COMPLETE_ID); target->htc_flags |= HTC_OP_START_WAIT; @@ -236,13 +245,14 @@ int htc_connect_service(struct htc_target *target, struct sk_buff *skb; struct htc_endpoint *endpoint; struct htc_conn_svc_msg *conn_msg; - int ret, time_left; + int ret; + unsigned long time_left; /* Find an available endpoint */ endpoint = get_next_avail_ep(target->endpoint); if (!endpoint) { - dev_err(target->dev, "Endpoint is not available for" - "service %d\n", service_connreq->service_id); + dev_err(target->dev, "Endpoint is not available for service %d\n", + service_connreq->service_id); return -EINVAL; } @@ -262,14 +272,17 @@ int htc_connect_service(struct htc_target *target, skb_reserve(skb, sizeof(struct htc_frame_hdr)); - conn_msg = (struct htc_conn_svc_msg *) - skb_put(skb, sizeof(struct htc_conn_svc_msg)); + conn_msg = skb_put(skb, sizeof(struct htc_conn_svc_msg)); conn_msg->service_id = cpu_to_be16(service_connreq->service_id); conn_msg->msg_id = cpu_to_be16(HTC_MSG_CONNECT_SERVICE_ID); conn_msg->con_flags = cpu_to_be16(service_connreq->con_flags); conn_msg->dl_pipeid = endpoint->dl_pipeid; conn_msg->ul_pipeid = endpoint->ul_pipeid; + /* To prevent infoleak */ + conn_msg->svc_meta_len = 0; + conn_msg->pad = 0; + ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0); if (ret) goto err; @@ -281,6 +294,9 @@ int htc_connect_service(struct htc_target *target, return -ETIMEDOUT; } + if (target->conn_rsp_epid < 0 || target->conn_rsp_epid >= ENDPOINT_MAX) + return -EINVAL; + *conn_rsp_epid = target->conn_rsp_epid; return 0; err: @@ -337,6 +353,8 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, if (skb) { htc_hdr = (struct htc_frame_hdr *) skb->data; + if (htc_hdr->endpoint_id >= ARRAY_SIZE(htc_handle->endpoint)) + goto ret; endpoint = &htc_handle->endpoint[htc_hdr->endpoint_id]; skb_pull(skb, sizeof(struct htc_frame_hdr)); @@ -351,18 +369,38 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, return; ret: - /* HTC-generated packets are freed here. */ - if (htc_hdr && htc_hdr->endpoint_id != ENDPOINT0) - dev_kfree_skb_any(skb); - else - kfree_skb(skb); + kfree_skb(skb); +} + +static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle, + struct sk_buff *skb, u32 len) +{ + uint32_t *pattern = (uint32_t *)skb->data; + + if (*pattern == 0x33221199 && len >= sizeof(struct htc_panic_bad_vaddr)) { + struct htc_panic_bad_vaddr *htc_panic; + htc_panic = (struct htc_panic_bad_vaddr *) skb->data; + dev_err(htc_handle->dev, "ath: firmware panic! " + "exccause: 0x%08x; pc: 0x%08x; badvaddr: 0x%08x.\n", + htc_panic->exccause, htc_panic->pc, + htc_panic->badvaddr); + return; + } + if (*pattern == 0x33221299) { + struct htc_panic_bad_epid *htc_panic; + htc_panic = (struct htc_panic_bad_epid *) skb->data; + dev_err(htc_handle->dev, "ath: firmware panic! " + "bad epid: 0x%08x\n", htc_panic->epid); + return; + } + dev_err(htc_handle->dev, "ath: unknown panic pattern!\n"); } /* * HTC Messages are handled directly here and the obtained SKB * is freed. * - * Service messages (Data, WMI) passed to the corresponding + * Service messages (Data, WMI) are passed to the corresponding * endpoint RX handlers, which have to free the SKB. */ void ath9k_htc_rx_msg(struct htc_target *htc_handle, @@ -376,10 +414,26 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle, if (!htc_handle || !skb) return; + /* A valid message requires len >= 8. + * + * sizeof(struct htc_frame_hdr) == 8 + * sizeof(struct htc_ready_msg) == 8 + * sizeof(struct htc_panic_bad_vaddr) == 16 + * sizeof(struct htc_panic_bad_epid) == 8 + */ + if (unlikely(len < sizeof(struct htc_frame_hdr))) + goto invalid; htc_hdr = (struct htc_frame_hdr *) skb->data; epid = htc_hdr->endpoint_id; - if (epid >= ENDPOINT_MAX) { + if (epid == 0x99) { + ath9k_htc_fw_panic_report(htc_handle, skb, len); + kfree_skb(skb); + return; + } + + if (epid < 0 || epid >= ENDPOINT_MAX) { +invalid: if (pipe_id != USB_REG_IN_PIPE) dev_kfree_skb_any(skb); else @@ -391,21 +445,30 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle, /* Handle trailer */ if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) { - if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000) + if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000) { /* Move past the Watchdog pattern */ htc_hdr = (struct htc_frame_hdr *)(skb->data + 4); + len -= 4; + } } /* Get the message ID */ + if (unlikely(len < sizeof(struct htc_frame_hdr) + sizeof(__be16))) + goto invalid; msg_id = (__be16 *) ((void *) htc_hdr + sizeof(struct htc_frame_hdr)); /* Now process HTC messages */ switch (be16_to_cpu(*msg_id)) { case HTC_MSG_READY_ID: + if (unlikely(len < sizeof(struct htc_ready_msg))) + goto invalid; htc_process_target_rdy(htc_handle, htc_hdr); break; case HTC_MSG_CONNECT_SERVICE_RESPONSE_ID: + if (unlikely(len < sizeof(struct htc_frame_hdr) + + sizeof(struct htc_conn_svc_rspmsg))) + goto invalid; htc_process_conn_rsp(htc_handle, htc_hdr); break; default: @@ -424,6 +487,8 @@ void ath9k_htc_rx_msg(struct htc_target *htc_handle, if (endpoint->ep_callbacks.rx) endpoint->ep_callbacks.rx(endpoint->ep_callbacks.priv, skb, epid); + else + goto invalid; } } diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h index e1ffbb6bd636..06474ccc7696 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.h +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h @@ -77,6 +77,18 @@ struct htc_config_pipe_msg { u8 credits; } __packed; +struct htc_panic_bad_vaddr { + __be32 pattern; + __be32 exccause; + __be32 pc; + __be32 badvaddr; +} __packed; + +struct htc_panic_bad_epid { + __be32 pattern; + __be32 epid; +} __packed; + struct htc_ep_callbacks { void *priv; void (*tx) (void *, struct sk_buff *, enum htc_endpoint_id, bool txok); diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 14b701140b49..232339b05540 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -41,17 +41,17 @@ static inline void ath9k_hw_set_desc_link(struct ath_hw *ah, void *ds, ath9k_hw_ops(ah)->set_desc_link(ds, link); } -static inline bool ath9k_hw_calibrate(struct ath_hw *ah, - struct ath9k_channel *chan, - u8 rxchainmask, - bool longcal) +static inline int ath9k_hw_calibrate(struct ath_hw *ah, + struct ath9k_channel *chan, + u8 rxchainmask, bool longcal) { return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal); } -static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) +static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked, + u32 *sync_cause_p) { - return ath9k_hw_ops(ah)->get_isr(ah, masked); + return ath9k_hw_ops(ah)->get_isr(ah, masked, sync_cause_p); } static inline void ath9k_hw_set_txdesc(struct ath_hw *ah, void *ds, @@ -66,6 +66,12 @@ static inline int ath9k_hw_txprocdesc(struct ath_hw *ah, void *ds, return ath9k_hw_ops(ah)->proc_txdesc(ah, ds, ts); } +static inline int ath9k_hw_get_duration(struct ath_hw *ah, const void *ds, + int index) +{ + return ath9k_hw_ops(ah)->get_duration(ah, ds, index); +} + static inline void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah, struct ath_hw_antcomb_conf *antconf) { @@ -78,15 +84,57 @@ static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah, ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf); } -static inline void ath9k_hw_antctrl_shared_chain_lnadiv(struct ath_hw *ah, - bool enable) +static inline void ath9k_hw_tx99_start(struct ath_hw *ah, u32 qnum) +{ + ath9k_hw_ops(ah)->tx99_start(ah, qnum); +} + +static inline void ath9k_hw_tx99_stop(struct ath_hw *ah) +{ + ath9k_hw_ops(ah)->tx99_stop(ah); +} + +static inline void ath9k_hw_tx99_set_txpower(struct ath_hw *ah, u8 power) +{ + if (ath9k_hw_ops(ah)->tx99_set_txpower) + ath9k_hw_ops(ah)->tx99_set_txpower(ah, power); +} + +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + +static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) +{ + if (ath9k_hw_ops(ah)->set_bt_ant_diversity) + ath9k_hw_ops(ah)->set_bt_ant_diversity(ah, enable); +} + +static inline bool ath9k_hw_is_aic_enabled(struct ath_hw *ah) { - if (ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv) - ath9k_hw_ops(ah)->antctrl_shared_chain_lnadiv(ah, enable); + if (ath9k_hw_private_ops(ah)->is_aic_enabled) + return ath9k_hw_private_ops(ah)->is_aic_enabled(ah); + + return false; } +#endif + /* Private hardware call ops */ +static inline void ath9k_hw_init_hang_checks(struct ath_hw *ah) +{ + ath9k_hw_private_ops(ah)->init_hang_checks(ah); +} + +static inline bool ath9k_hw_detect_mac_hang(struct ath_hw *ah) +{ + return ath9k_hw_private_ops(ah)->detect_mac_hang(ah); +} + +static inline bool ath9k_hw_detect_bb_hang(struct ath_hw *ah) +{ + return ath9k_hw_private_ops(ah)->detect_bb_hang(ah); +} + /* PHY ops */ static inline int ath9k_hw_rf_set_freq(struct ath_hw *ah, @@ -212,4 +260,31 @@ static inline void ath9k_hw_set_radar_params(struct ath_hw *ah) ath9k_hw_private_ops(ah)->set_radar_params(ah, &ah->radar_conf); } +static inline void ath9k_hw_init_cal_settings(struct ath_hw *ah) +{ + ath9k_hw_private_ops(ah)->init_cal_settings(ah); +} + +static inline u32 ath9k_hw_compute_pll_control(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + return ath9k_hw_private_ops(ah)->compute_pll_control(ah, chan); +} + +static inline void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah) +{ + if (!ath9k_hw_private_ops(ah)->init_mode_gain_regs) + return; + + ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah); +} + +static inline void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah) +{ + if (!ath9k_hw_private_ops(ah)->ani_cache_ini_regs) + return; + + ath9k_hw_private_ops(ah)->ani_cache_ini_regs(ah); +} + #endif /* ATH9K_HW_OPS_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 4ca0cb060106..14de62c1a32b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -14,145 +14,53 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/export.h> #include <linux/io.h> #include <linux/slab.h> #include <linux/module.h> -#include <asm/unaligned.h> +#include <linux/time.h> +#include <linux/bitops.h> +#include <linux/etherdevice.h> +#include <linux/gpio.h> +#include <linux/unaligned.h> #include "hw.h" #include "hw-ops.h" -#include "rc.h" #include "ar9003_mac.h" #include "ar9003_mci.h" #include "ar9003_phy.h" -#include "debug.h" #include "ath9k.h" static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type); MODULE_AUTHOR("Atheros Communications"); MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); -MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); MODULE_LICENSE("Dual BSD/GPL"); -static int __init ath9k_init(void) -{ - return 0; -} -module_init(ath9k_init); - -static void __exit ath9k_exit(void) -{ - return; -} -module_exit(ath9k_exit); - -/* Private hardware callbacks */ - -static void ath9k_hw_init_cal_settings(struct ath_hw *ah) -{ - ath9k_hw_private_ops(ah)->init_cal_settings(ah); -} - -static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - return ath9k_hw_private_ops(ah)->compute_pll_control(ah, chan); -} - -static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah) -{ - if (!ath9k_hw_private_ops(ah)->init_mode_gain_regs) - return; - - ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah); -} - -static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah) -{ - /* You will not have this callback if using the old ANI */ - if (!ath9k_hw_private_ops(ah)->ani_cache_ini_regs) - return; - - ath9k_hw_private_ops(ah)->ani_cache_ini_regs(ah); -} - -/********************/ -/* Helper Functions */ -/********************/ - -#ifdef CONFIG_ATH9K_DEBUGFS - -void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause) -{ - struct ath_softc *sc = common->priv; - if (sync_cause) - sc->debug.stats.istats.sync_cause_all++; - if (sync_cause & AR_INTR_SYNC_RTC_IRQ) - sc->debug.stats.istats.sync_rtc_irq++; - if (sync_cause & AR_INTR_SYNC_MAC_IRQ) - sc->debug.stats.istats.sync_mac_irq++; - if (sync_cause & AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS) - sc->debug.stats.istats.eeprom_illegal_access++; - if (sync_cause & AR_INTR_SYNC_APB_TIMEOUT) - sc->debug.stats.istats.apb_timeout++; - if (sync_cause & AR_INTR_SYNC_PCI_MODE_CONFLICT) - sc->debug.stats.istats.pci_mode_conflict++; - if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) - sc->debug.stats.istats.host1_fatal++; - if (sync_cause & AR_INTR_SYNC_HOST1_PERR) - sc->debug.stats.istats.host1_perr++; - if (sync_cause & AR_INTR_SYNC_TRCV_FIFO_PERR) - sc->debug.stats.istats.trcv_fifo_perr++; - if (sync_cause & AR_INTR_SYNC_RADM_CPL_EP) - sc->debug.stats.istats.radm_cpl_ep++; - if (sync_cause & AR_INTR_SYNC_RADM_CPL_DLLP_ABORT) - sc->debug.stats.istats.radm_cpl_dllp_abort++; - if (sync_cause & AR_INTR_SYNC_RADM_CPL_TLP_ABORT) - sc->debug.stats.istats.radm_cpl_tlp_abort++; - if (sync_cause & AR_INTR_SYNC_RADM_CPL_ECRC_ERR) - sc->debug.stats.istats.radm_cpl_ecrc_err++; - if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) - sc->debug.stats.istats.radm_cpl_timeout++; - if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) - sc->debug.stats.istats.local_timeout++; - if (sync_cause & AR_INTR_SYNC_PM_ACCESS) - sc->debug.stats.istats.pm_access++; - if (sync_cause & AR_INTR_SYNC_MAC_AWAKE) - sc->debug.stats.istats.mac_awake++; - if (sync_cause & AR_INTR_SYNC_MAC_ASLEEP) - sc->debug.stats.istats.mac_asleep++; - if (sync_cause & AR_INTR_SYNC_MAC_SLEEP_ACCESS) - sc->debug.stats.istats.mac_sleep_access++; -} -#endif - - static void ath9k_hw_set_clockrate(struct ath_hw *ah) { - struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_channel *chan = ah->curchan; unsigned int clockrate; /* AR9287 v1.3+ uses async FIFO and runs the MAC at 117 MHz */ if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) clockrate = 117; - else if (!ah->curchan) /* should really check for CCK instead */ + else if (!chan) /* should really check for CCK instead */ clockrate = ATH9K_CLOCK_RATE_CCK; - else if (conf->chandef.chan->band == IEEE80211_BAND_2GHZ) + else if (IS_CHAN_2GHZ(chan)) clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM; else if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK) clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM; else clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM; - if (conf_is_ht40(conf)) - clockrate *= 2; - - if (ah->curchan) { - if (IS_CHAN_HALF_RATE(ah->curchan)) + if (chan) { + if (IS_CHAN_HT40(chan)) + clockrate *= 2; + if (IS_CHAN_HALF_RATE(chan)) clockrate /= 2; - if (IS_CHAN_QUARTER_RATE(ah->curchan)) + if (IS_CHAN_QUARTER_RATE(chan)) clockrate /= 4; } @@ -190,10 +98,7 @@ EXPORT_SYMBOL(ath9k_hw_wait); void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan, int hw_delay) { - if (IS_CHAN_B(chan)) - hw_delay = (4 * hw_delay) / 22; - else - hw_delay /= 10; + hw_delay /= 10; if (IS_CHAN_HALF_RATE(chan)) hw_delay *= 2; @@ -217,6 +122,36 @@ void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array, REGWRITE_BUFFER_FLUSH(ah); } +void ath9k_hw_read_array(struct ath_hw *ah, u32 array[][2], int size) +{ + u32 *tmp_reg_list, *tmp_data; + int i; + + tmp_reg_list = kmalloc_array(size, sizeof(u32), GFP_KERNEL); + if (!tmp_reg_list) { + dev_err(ah->dev, "%s: tmp_reg_list: alloc filed\n", __func__); + return; + } + + tmp_data = kmalloc_array(size, sizeof(u32), GFP_KERNEL); + if (!tmp_data) { + dev_err(ah->dev, "%s tmp_data: alloc filed\n", __func__); + goto error_tmp_data; + } + + for (i = 0; i < size; i++) + tmp_reg_list[i] = array[i][0]; + + REG_READ_MULTI(ah, tmp_reg_list, tmp_data, size); + + for (i = 0; i < size; i++) + array[i][1] = tmp_data[i]; + + kfree(tmp_data); +error_tmp_data: + kfree(tmp_reg_list); +} + u32 ath9k_hw_reverse_bits(u32 val, u32 n) { u32 retval; @@ -249,7 +184,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah, break; case WLAN_RC_PHY_OFDM: if (ah->curchan && IS_CHAN_QUARTER_RATE(ah->curchan)) { - bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; + bitsPerSymbol = + ((kbps >> 2) * OFDM_SYMBOL_TIME_QUARTER) / 1000; numBits = OFDM_PLCP_BITS + (frameLen << 3); numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); txTime = OFDM_SIFS_TIME_QUARTER @@ -257,7 +193,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah, + (numSymbols * OFDM_SYMBOL_TIME_QUARTER); } else if (ah->curchan && IS_CHAN_HALF_RATE(ah->curchan)) { - bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; + bitsPerSymbol = + ((kbps >> 1) * OFDM_SYMBOL_TIME_HALF) / 1000; numBits = OFDM_PLCP_BITS + (frameLen << 3); numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); txTime = OFDM_SIFS_TIME_HALF + @@ -294,8 +231,7 @@ void ath9k_hw_get_channel_centers(struct ath_hw *ah, return; } - if ((chan->chanmode == CHANNEL_A_HT40PLUS) || - (chan->chanmode == CHANNEL_G_HT40PLUS)) { + if (IS_CHAN_HT40PLUS(chan)) { centers->synth_center = chan->channel + HT40_CHANNEL_CENTER_SHIFT; extoff = 1; @@ -316,37 +252,51 @@ void ath9k_hw_get_channel_centers(struct ath_hw *ah, /* Chip Revisions */ /******************/ -static void ath9k_hw_read_revisions(struct ath_hw *ah) +static bool ath9k_hw_read_revisions(struct ath_hw *ah) { + u32 srev; u32 val; + if (ah->get_mac_revision) + ah->hw_version.macRev = ah->get_mac_revision(); + switch (ah->hw_version.devid) { case AR5416_AR9100_DEVID: ah->hw_version.macVersion = AR_SREV_VERSION_9100; break; case AR9300_DEVID_AR9330: ah->hw_version.macVersion = AR_SREV_VERSION_9330; - if (ah->get_mac_revision) { - ah->hw_version.macRev = ah->get_mac_revision(); - } else { - val = REG_READ(ah, AR_SREV); + if (!ah->get_mac_revision) { + val = REG_READ(ah, AR_SREV(ah)); ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); } - return; + return true; case AR9300_DEVID_AR9340: ah->hw_version.macVersion = AR_SREV_VERSION_9340; - val = REG_READ(ah, AR_SREV); - ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); - return; + return true; case AR9300_DEVID_QCA955X: ah->hw_version.macVersion = AR_SREV_VERSION_9550; - return; + return true; + case AR9300_DEVID_AR953X: + ah->hw_version.macVersion = AR_SREV_VERSION_9531; + return true; + case AR9300_DEVID_QCA956X: + ah->hw_version.macVersion = AR_SREV_VERSION_9561; + return true; } - val = REG_READ(ah, AR_SREV) & AR_SREV_ID; + srev = REG_READ(ah, AR_SREV(ah)); + + if (srev == -1) { + ath_err(ath9k_hw_common(ah), + "Failed to read SREV register"); + return false; + } + + val = srev & AR_SREV_ID(ah); if (val == 0xFF) { - val = REG_READ(ah, AR_SREV); + val = srev; ah->hw_version.macVersion = (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); @@ -365,6 +315,8 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE) ah->is_pciexpress = true; } + + return true; } /************************************/ @@ -442,24 +394,25 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah) static void ath9k_hw_init_config(struct ath_hw *ah) { - int i; + struct ath_common *common = ath9k_hw_common(ah); ah->config.dma_beacon_response_time = 1; ah->config.sw_beacon_response_time = 6; - ah->config.additional_swba_backoff = 0; - ah->config.ack_6mb = 0x0; - ah->config.cwm_ignore_extcca = 0; - ah->config.pcie_clock_req = 0; - ah->config.pcie_waen = 0; + ah->config.cwm_ignore_extcca = false; ah->config.analog_shiftreg = 1; - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - ah->config.spurchans[i][0] = AR_NO_SPUR; - ah->config.spurchans[i][1] = AR_NO_SPUR; + ah->config.rx_intr_mitigation = true; + + if (AR_SREV_9300_20_OR_LATER(ah)) { + ah->config.rimt_last = 500; + ah->config.rimt_first = 2000; + } else { + ah->config.rimt_last = 250; + ah->config.rimt_first = 700; } - ah->config.rx_intr_mitigation = true; - ah->config.pcieSerDesWrite = true; + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) + ah->config.pll_pwrsave = 7; /* * We need this for PCI devices only (Cardbus, PCI, miniPCI) @@ -479,6 +432,24 @@ static void ath9k_hw_init_config(struct ath_hw *ah) */ if (num_possible_cpus() > 1) ah->config.serialize_regmode = SER_REG_MODE_AUTO; + + if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) { + if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || + ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) && + !ah->is_pciexpress)) { + ah->config.serialize_regmode = SER_REG_MODE_ON; + } else { + ah->config.serialize_regmode = SER_REG_MODE_OFF; + } + } + + ath_dbg(common, RESET, "serialize_regmode is %d\n", + ah->config.serialize_regmode); + + if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) + ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1; + else + ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD; } static void ath9k_hw_init_defaults(struct ath_hw *ah) @@ -486,42 +457,61 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); regulatory->country_code = CTRY_DEFAULT; - regulatory->power_limit = MAX_RATE_POWER; + regulatory->power_limit = MAX_COMBINED_POWER; ah->hw_version.magic = AR5416_MAGIC; ah->hw_version.subvendorid = 0; - ah->atim_window = 0; - ah->sta_id1_defaults = - AR_STA_ID1_CRPT_MIC_ENABLE | - AR_STA_ID1_MCAST_KSRCH; + ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE | + AR_STA_ID1_MCAST_KSRCH; if (AR_SREV_9100(ah)) ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX; - ah->slottime = ATH9K_SLOT_TIME_9; + + ah->slottime = 9; ah->globaltxtimeout = (u32) -1; ah->power_mode = ATH9K_PM_UNDEFINED; ah->htc_reset_init = true; + + ah->tpc_enabled = false; + + ah->ani_function = ATH9K_ANI_ALL; + if (!AR_SREV_9300_20_OR_LATER(ah)) + ah->ani_function &= ~ATH9K_ANI_MRC_CCK; + + if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) + ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S); + else + ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S); } -static int ath9k_hw_init_macaddr(struct ath_hw *ah) +static void ath9k_hw_init_macaddr(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - u32 sum; int i; u16 eeval; static const u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW }; - sum = 0; + /* MAC address may already be loaded via NVMEM */ + if (is_valid_ether_addr(common->macaddr)) + return; + for (i = 0; i < 3; i++) { eeval = ah->eep_ops->get_eeprom(ah, EEP_MAC[i]); - sum += eeval; common->macaddr[2 * i] = eeval >> 8; common->macaddr[2 * i + 1] = eeval & 0xff; } - if (sum == 0 || sum == 0xffff * 3) - return -EADDRNOTAVAIL; - return 0; + if (is_valid_ether_addr(common->macaddr)) + return; + + ath_err(common, "eeprom contains invalid mac address: %pM\n", + common->macaddr); + + eth_random_addr(common->macaddr); + ath_err(common, "random mac address will be used: %pM\n", + common->macaddr); + + return; } static int ath9k_hw_post_init(struct ath_hw *ah) @@ -550,6 +540,18 @@ static int ath9k_hw_post_init(struct ath_hw *ah) ath9k_hw_ani_init(ah); + /* + * EEPROM needs to be initialized before we do this. + * This is required for regulatory compliance. + */ + if (AR_SREV_9300_20_OR_LATER(ah)) { + u16 regdmn = ah->eep_ops->get_eeprom(ah, EEP_REG_0); + if ((regdmn & 0xF0) == CTL_FCC) { + ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_2GHZ; + ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_5GHZ; + } + } + return 0; } @@ -568,28 +570,56 @@ static int __ath9k_hw_init(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); int r = 0; - ath9k_hw_read_revisions(ah); + if (!ath9k_hw_read_revisions(ah)) { + ath_err(common, "Could not read hardware revisions"); + return -EOPNOTSUPP; + } + + switch (ah->hw_version.macVersion) { + case AR_SREV_VERSION_5416_PCI: + case AR_SREV_VERSION_5416_PCIE: + case AR_SREV_VERSION_9160: + case AR_SREV_VERSION_9100: + case AR_SREV_VERSION_9280: + case AR_SREV_VERSION_9285: + case AR_SREV_VERSION_9287: + case AR_SREV_VERSION_9271: + case AR_SREV_VERSION_9300: + case AR_SREV_VERSION_9330: + case AR_SREV_VERSION_9485: + case AR_SREV_VERSION_9340: + case AR_SREV_VERSION_9462: + case AR_SREV_VERSION_9550: + case AR_SREV_VERSION_9565: + case AR_SREV_VERSION_9531: + case AR_SREV_VERSION_9561: + break; + default: + ath_err(common, + "Mac Chip Rev 0x%02x.%x is not supported by this driver\n", + ah->hw_version.macVersion, ah->hw_version.macRev); + return -EOPNOTSUPP; + } /* - * Read back AR_WA into a permanent copy and set bits 14 and 17. + * Read back AR_WA(ah) into a permanent copy and set bits 14 and 17. * We need to do this to avoid RMW of this register. We cannot * read the reg when chip is asleep. */ - ah->WARegVal = REG_READ(ah, AR_WA); - ah->WARegVal |= (AR_WA_D3_L1_DISABLE | - AR_WA_ASPM_TIMER_BASED_DISABLE); + if (AR_SREV_9300_20_OR_LATER(ah)) { + ah->WARegVal = REG_READ(ah, AR_WA(ah)); + ah->WARegVal |= (AR_WA_D3_L1_DISABLE | + AR_WA_ASPM_TIMER_BASED_DISABLE); + } if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { ath_err(common, "Couldn't reset chip\n"); return -EIO; } - if (AR_SREV_9462(ah)) - ah->WARegVal &= ~AR_WA_D3_L1_DISABLE; - if (AR_SREV_9565(ah)) { ah->WARegVal |= AR_WA_BIT22; - REG_WRITE(ah, AR_WA, ah->WARegVal); + REG_WRITE(ah, AR_WA(ah), ah->WARegVal); } ath9k_hw_init_defaults(ah); @@ -604,50 +634,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) return -EIO; } - if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) { - if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || - ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) && - !ah->is_pciexpress)) { - ah->config.serialize_regmode = - SER_REG_MODE_ON; - } else { - ah->config.serialize_regmode = - SER_REG_MODE_OFF; - } - } - - ath_dbg(common, RESET, "serialize_regmode is %d\n", - ah->config.serialize_regmode); - - if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) - ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1; - else - ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD; - - switch (ah->hw_version.macVersion) { - case AR_SREV_VERSION_5416_PCI: - case AR_SREV_VERSION_5416_PCIE: - case AR_SREV_VERSION_9160: - case AR_SREV_VERSION_9100: - case AR_SREV_VERSION_9280: - case AR_SREV_VERSION_9285: - case AR_SREV_VERSION_9287: - case AR_SREV_VERSION_9271: - case AR_SREV_VERSION_9300: - case AR_SREV_VERSION_9330: - case AR_SREV_VERSION_9485: - case AR_SREV_VERSION_9340: - case AR_SREV_VERSION_9462: - case AR_SREV_VERSION_9550: - case AR_SREV_VERSION_9565: - break; - default: - ath_err(common, - "Mac Chip Rev 0x%02x.%x is not supported by this driver\n", - ah->hw_version.macVersion, ah->hw_version.macRev); - return -EOPNOTSUPP; - } - if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || AR_SREV_9550(ah)) ah->is_pciexpress = false; @@ -655,12 +641,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); ath9k_hw_init_cal_settings(ah); - ah->ani_function = ATH9K_ANI_ALL; - if (AR_SREV_9280_20_OR_LATER(ah) && !AR_SREV_9300_20_OR_LATER(ah)) - ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; - if (!AR_SREV_9300_20_OR_LATER(ah)) - ah->ani_function &= ~ATH9K_ANI_MRC_CCK; - if (!ah->is_pciexpress) ath9k_hw_disablepcie(ah); @@ -673,21 +653,8 @@ static int __ath9k_hw_init(struct ath_hw *ah) if (r) return r; - r = ath9k_hw_init_macaddr(ah); - if (r) { - ath_err(common, "Failed to initialize MAC address\n"); - return r; - } - - if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) - ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S); - else - ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S); - - if (AR_SREV_9330(ah)) - ah->bb_watchdog_timeout_ms = 85; - else - ah->bb_watchdog_timeout_ms = 25; + ath9k_hw_init_macaddr(ah); + ath9k_hw_init_hang_checks(ah); common->state = ATH_HW_INITIALIZED; @@ -720,6 +687,8 @@ int ath9k_hw_init(struct ath_hw *ah) case AR9300_DEVID_AR9462: case AR9485_DEVID_AR1111: case AR9300_DEVID_AR9565: + case AR9300_DEVID_AR953X: + case AR9300_DEVID_QCA956X: break; default: if (common->bus_ops->ath_bus_type == ATH_USB) @@ -737,6 +706,8 @@ int ath9k_hw_init(struct ath_hw *ah) return ret; } + ath_dynack_init(ah); + return 0; } EXPORT_SYMBOL(ath9k_hw_init); @@ -776,7 +747,7 @@ u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) udelay(100); if (WARN_ON_ONCE(i >= 100)) { - ath_err(common, "PLL4 meaurement not done\n"); + ath_err(common, "PLL4 measurement not done\n"); break; } @@ -792,6 +763,8 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, { u32 pll; + pll = ath9k_hw_compute_pll_control(ah, chan); + if (AR_SREV_9485(ah) || AR_SREV_9565(ah)) { /* program BB PLL ki and kd value, ki=0x4, kd=0x40 */ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, @@ -842,7 +815,8 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_CH0_DDR_DPLL3, AR_CH0_DPLL3_PHASE_SHIFT, 0x1); - REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); + REG_WRITE(ah, AR_RTC_PLL_CONTROL(ah), + pll | AR_RTC_9300_PLL_BYPASS); udelay(1000); /* program refdiv, nint, frac to RTC register */ @@ -855,19 +829,27 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, /* program BB PLL phase_shift */ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x1); - } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) { + } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) { u32 regval, pll2_divint, pll2_divfrac, refdiv; - REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); + REG_WRITE(ah, AR_RTC_PLL_CONTROL(ah), + pll | AR_RTC_9300_SOC_PLL_BYPASS); udelay(1000); REG_SET_BIT(ah, AR_PHY_PLL_MODE, 0x1 << 16); udelay(100); if (ah->is_clk_25mhz) { - pll2_divint = 0x54; - pll2_divfrac = 0x1eb85; - refdiv = 3; + if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) { + pll2_divint = 0x1c; + pll2_divfrac = 0xa3d2; + refdiv = 1; + } else { + pll2_divint = 0x54; + pll2_divfrac = 0x1eb85; + refdiv = 3; + } } else { if (AR_SREV_9340(ah)) { pll2_divint = 88; @@ -875,13 +857,18 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, refdiv = 5; } else { pll2_divint = 0x11; - pll2_divfrac = 0x26666; + pll2_divfrac = (AR_SREV_9531(ah) || + AR_SREV_9561(ah)) ? + 0x26665 : 0x26666; refdiv = 1; } } regval = REG_READ(ah, AR_PHY_PLL_MODE); - regval |= (0x1 << 16); + if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) + regval |= (0x1 << 22); + else + regval |= (0x1 << 16); REG_WRITE(ah, AR_PHY_PLL_MODE, regval); udelay(100); @@ -891,21 +878,41 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, regval = REG_READ(ah, AR_PHY_PLL_MODE); if (AR_SREV_9340(ah)) - regval = (regval & 0x80071fff) | (0x1 << 30) | - (0x1 << 13) | (0x4 << 26) | (0x18 << 19); - else - regval = (regval & 0x80071fff) | (0x3 << 30) | - (0x1 << 13) | (0x4 << 26) | (0x60 << 19); + regval = (regval & 0x80071fff) | + (0x1 << 30) | + (0x1 << 13) | + (0x4 << 26) | + (0x18 << 19); + else if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) { + regval = (regval & 0x01c00fff) | + (0x1 << 31) | + (0x2 << 29) | + (0xa << 25) | + (0x1 << 19); + + if (AR_SREV_9531(ah)) + regval |= (0x6 << 12); + } else + regval = (regval & 0x80071fff) | + (0x3 << 30) | + (0x1 << 13) | + (0x4 << 26) | + (0x60 << 19); REG_WRITE(ah, AR_PHY_PLL_MODE, regval); - REG_WRITE(ah, AR_PHY_PLL_MODE, - REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff); + + if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) + REG_WRITE(ah, AR_PHY_PLL_MODE, + REG_READ(ah, AR_PHY_PLL_MODE) & 0xffbfffff); + else + REG_WRITE(ah, AR_PHY_PLL_MODE, + REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff); + udelay(1000); } - pll = ath9k_hw_compute_pll_control(ah, chan); if (AR_SREV_9565(ah)) pll |= 0x40000; - REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); + REG_WRITE(ah, AR_RTC_PLL_CONTROL(ah), pll); if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || AR_SREV_9550(ah)) @@ -919,20 +926,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, udelay(RTC_PLL_SETTLE_DELAY); - REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); - - if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) { - if (ah->is_clk_25mhz) { - REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1); - REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); - REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae); - } else { - REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1); - REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400); - REG_WRITE(ah, AR_SLP32_INC, 0x0001e800); - } - udelay(100); - } + REG_WRITE(ah, AR_RTC_SLEEP_CLK(ah), AR_RTC_FORCE_DERIVED_CLK); } static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, @@ -944,28 +938,38 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, AR_IMR_RXERR | AR_IMR_RXORN | AR_IMR_BCNMISC; + u32 msi_cfg = 0; - if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; if (AR_SREV_9300_20_OR_LATER(ah)) { imr_reg |= AR_IMR_RXOK_HP; - if (ah->config.rx_intr_mitigation) + if (ah->config.rx_intr_mitigation) { imr_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; - else + msi_cfg |= AR_INTCFG_MSI_RXINTM | AR_INTCFG_MSI_RXMINTR; + } else { imr_reg |= AR_IMR_RXOK_LP; - + msi_cfg |= AR_INTCFG_MSI_RXOK; + } } else { - if (ah->config.rx_intr_mitigation) + if (ah->config.rx_intr_mitigation) { imr_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; - else + msi_cfg |= AR_INTCFG_MSI_RXINTM | AR_INTCFG_MSI_RXMINTR; + } else { imr_reg |= AR_IMR_RXOK; + msi_cfg |= AR_INTCFG_MSI_RXOK; + } } - if (ah->config.tx_intr_mitigation) + if (ah->config.tx_intr_mitigation) { imr_reg |= AR_IMR_TXINTM | AR_IMR_TXMINTR; - else + msi_cfg |= AR_INTCFG_MSI_TXINTM | AR_INTCFG_MSI_TXMINTR; + } else { imr_reg |= AR_IMR_TXOK; + msi_cfg |= AR_INTCFG_MSI_TXOK; + } ENABLE_REGWRITE_BUFFER(ah); @@ -973,19 +977,29 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, ah->imrs2_reg |= AR_IMR_S2_GTT; REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg); + if (ah->msi_enabled) { + ah->msi_reg = REG_READ(ah, AR_PCIE_MSI(ah)); + ah->msi_reg |= AR_PCIE_MSI_HW_DBI_WR_EN; + ah->msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64; + REG_WRITE(ah, AR_INTCFG, msi_cfg); + ath_dbg(ath9k_hw_common(ah), ANY, + "value of AR_INTCFG=0x%X, msi_cfg=0x%X\n", + REG_READ(ah, AR_INTCFG), msi_cfg); + } + if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF); - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default); - REG_WRITE(ah, AR_INTR_SYNC_MASK, 0); + REG_WRITE(ah, AR_INTR_SYNC_CAUSE(ah), 0xFFFFFFFF); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE(ah), sync_default); + REG_WRITE(ah, AR_INTR_SYNC_MASK(ah), 0); } REGWRITE_BUFFER_FLUSH(ah); if (AR_SREV_9300_20_OR_LATER(ah)) { - REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE, 0); - REG_WRITE(ah, AR_INTR_PRIO_ASYNC_MASK, 0); - REG_WRITE(ah, AR_INTR_PRIO_SYNC_ENABLE, 0); - REG_WRITE(ah, AR_INTR_PRIO_SYNC_MASK, 0); + REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE(ah), 0); + REG_WRITE(ah, AR_INTR_PRIO_ASYNC_MASK(ah), 0); + REG_WRITE(ah, AR_INTR_PRIO_SYNC_ENABLE(ah), 0); + REG_WRITE(ah, AR_INTR_PRIO_SYNC_MASK(ah), 0); } } @@ -996,21 +1010,21 @@ static void ath9k_hw_set_sifs_time(struct ath_hw *ah, u32 us) REG_WRITE(ah, AR_D_GBL_IFS_SIFS, val); } -static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us) +void ath9k_hw_setslottime(struct ath_hw *ah, u32 us) { u32 val = ath9k_hw_mac_to_clks(ah, us); val = min(val, (u32) 0xFFFF); REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val); } -static void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) +void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) { u32 val = ath9k_hw_mac_to_clks(ah, us); val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK)); REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val); } -static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) +void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) { u32 val = ath9k_hw_mac_to_clks(ah, us); val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS)); @@ -1034,12 +1048,11 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) void ath9k_hw_init_global_settings(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_conf *conf = &common->hw->conf; const struct ath9k_channel *chan = ah->curchan; int acktimeout, ctstimeout, ack_offset = 0; int slottime; int sifstime; - int rx_lat = 0, tx_lat = 0, eifs = 0; + int rx_lat = 0, tx_lat = 0, eifs = 0, ack_shift = 0; u32 reg; ath_dbg(ath9k_hw_common(ah), RESET, "ah->misc_mode 0x%x\n", @@ -1069,8 +1082,9 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) if (IS_CHAN_A_FAST_CLOCK(ah, chan)) tx_lat += 11; - sifstime *= 2; + sifstime = 32; ack_offset = 16; + ack_shift = 3; slottime = 13; } else if (IS_CHAN_QUARTER_RATE(chan)) { eifs = 340; @@ -1079,8 +1093,9 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) if (IS_CHAN_A_FAST_CLOCK(ah, chan)) tx_lat += 22; - sifstime *= 4; + sifstime = 64; ack_offset = 32; + ack_shift = 1; slottime = 21; } else { if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) { @@ -1109,13 +1124,19 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) * BA frames in some implementations, but it has been found to fix ACK * timeout issues in other cases as well. */ - if (conf->chandef.chan && - conf->chandef.chan->band == IEEE80211_BAND_2GHZ && + if (IS_CHAN_2GHZ(chan) && !IS_CHAN_HALF_RATE(chan) && !IS_CHAN_QUARTER_RATE(chan)) { acktimeout += 64 - sifstime - ah->slottime; ctstimeout += 48 - sifstime - ah->slottime; } + if (ah->dynack.enabled) { + acktimeout = ah->dynack.ackto; + ctstimeout = acktimeout; + slottime = (acktimeout - 3) / 2; + } else { + ah->dynack.ackto = acktimeout; + } ath9k_hw_set_sifs_time(ah, sifstime); ath9k_hw_setslottime(ah, slottime); @@ -1131,6 +1152,10 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) SM(tx_lat, AR_USEC_TX_LAT), AR_USEC_TX_LAT | AR_USEC_RX_LAT | AR_USEC_USEC); + if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) + REG_RMW(ah, AR_TXSIFS, + sifstime | SM(ack_shift, AR_TXSIFS_ACK_SHIFT), + (AR_TXSIFS_TIME | AR_TXSIFS_ACK_SHIFT)); } EXPORT_SYMBOL(ath9k_hw_init_global_settings); @@ -1153,9 +1178,7 @@ u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan) { u32 ctl = ath_regd_get_band_ctl(reg, chan->chan->band); - if (IS_CHAN_B(chan)) - ctl |= CTL_11B; - else if (IS_CHAN_G(chan)) + if (IS_CHAN_2GHZ(chan)) ctl |= CTL_11G; else ctl |= CTL_11A; @@ -1246,15 +1269,20 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) u32 mask = AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC; u32 set = AR_STA_ID1_KSRCH_MODE; + ENABLE_REG_RMW_BUFFER(ah); switch (opmode) { case NL80211_IFTYPE_ADHOC: - set |= AR_STA_ID1_ADHOC; - REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); - break; + if (!AR_SREV_9340_13(ah)) { + set |= AR_STA_ID1_ADHOC; + REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); + break; + } + fallthrough; + case NL80211_IFTYPE_OCB: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: set |= AR_STA_ID1_STA_AP; - /* fall through */ + fallthrough; case NL80211_IFTYPE_STATION: REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; @@ -1264,6 +1292,7 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) break; } REG_RMW(ah, AR_STA_ID1, set, mask); + REG_RMW_BUFFER_FLUSH(ah); } void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, @@ -1283,32 +1312,68 @@ void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, *coef_exponent = coef_exp - 16; } +/* AR9330 WAR: + * call external reset function to reset WMAC if: + * - doing a cold reset + * - we have pending frames in the TX queues. + */ +static bool ath9k_hw_ar9330_reset_war(struct ath_hw *ah, int type) +{ + int i, npend = 0; + + for (i = 0; i < AR_NUM_QCU; i++) { + npend = ath9k_hw_numtxpending(ah, i); + if (npend) + break; + } + + if (ah->external_reset && + (npend || type == ATH9K_RESET_COLD)) { + int reset_err = 0; + + ath_dbg(ath9k_hw_common(ah), RESET, + "reset MAC via external reset\n"); + + reset_err = ah->external_reset(); + if (reset_err) { + ath_err(ath9k_hw_common(ah), + "External reset failed, err=%d\n", + reset_err); + return false; + } + + REG_WRITE(ah, AR_RTC_RESET(ah), 1); + } + + return true; +} + static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) { u32 rst_flags; u32 tmpReg; if (AR_SREV_9100(ah)) { - REG_RMW_FIELD(ah, AR_RTC_DERIVED_CLK, + REG_RMW_FIELD(ah, AR_RTC_DERIVED_CLK(ah), AR_RTC_DERIVED_CLK_PERIOD, 1); - (void)REG_READ(ah, AR_RTC_DERIVED_CLK); + (void)REG_READ(ah, AR_RTC_DERIVED_CLK(ah)); } ENABLE_REGWRITE_BUFFER(ah); if (AR_SREV_9300_20_OR_LATER(ah)) { - REG_WRITE(ah, AR_WA, ah->WARegVal); + REG_WRITE(ah, AR_WA(ah), ah->WARegVal); udelay(10); } - REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | + REG_WRITE(ah, AR_RTC_FORCE_WAKE(ah), AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); if (AR_SREV_9100(ah)) { rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD | AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET; } else { - tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE); + tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE(ah)); if (AR_SREV_9340(ah)) tmpReg &= AR9340_INTR_SYNC_LOCAL_TIMEOUT; else @@ -1317,7 +1382,7 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) if (tmpReg) { u32 val; - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE(ah), 0); val = AR_RC_HOSTIF; if (!AR_SREV_9300_20_OR_LATER(ah)) @@ -1333,51 +1398,36 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) } if (AR_SREV_9330(ah)) { - int npend = 0; - int i; - - /* AR9330 WAR: - * call external reset function to reset WMAC if: - * - doing a cold reset - * - we have pending frames in the TX queues - */ - - for (i = 0; i < AR_NUM_QCU; i++) { - npend = ath9k_hw_numtxpending(ah, i); - if (npend) - break; - } - - if (ah->external_reset && - (npend || type == ATH9K_RESET_COLD)) { - int reset_err = 0; - - ath_dbg(ath9k_hw_common(ah), RESET, - "reset MAC via external reset\n"); - - reset_err = ah->external_reset(); - if (reset_err) { - ath_err(ath9k_hw_common(ah), - "External reset failed, err=%d\n", - reset_err); - return false; - } - - REG_WRITE(ah, AR_RTC_RESET, 1); - } + if (!ath9k_hw_ar9330_reset_war(ah, type)) + return false; } if (ath9k_hw_mci_is_enabled(ah)) ar9003_mci_check_gpm_offset(ah); - REG_WRITE(ah, AR_RTC_RC, rst_flags); + /* DMA HALT added to resolve ar9300 and ar9580 bus error during + * RTC_RC reg read + */ + if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) { + REG_SET_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); + ath9k_hw_wait(ah, AR_CFG, AR_CFG_HALT_ACK, AR_CFG_HALT_ACK, + 20 * AH_WAIT_TIMEOUT); + REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); + } + + REG_WRITE(ah, AR_RTC_RC(ah), rst_flags); REGWRITE_BUFFER_FLUSH(ah); - udelay(50); + if (AR_SREV_9300_20_OR_LATER(ah)) + udelay(50); + else if (AR_SREV_9100(ah)) + mdelay(10); + else + udelay(100); - REG_WRITE(ah, AR_RTC_RC, 0); - if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) { + REG_WRITE(ah, AR_RTC_RC(ah), 0); + if (!ath9k_hw_wait(ah, AR_RTC_RC(ah), AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) { ath_dbg(ath9k_hw_common(ah), RESET, "RTC stuck in MAC reset\n"); return false; } @@ -1396,31 +1446,30 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) ENABLE_REGWRITE_BUFFER(ah); if (AR_SREV_9300_20_OR_LATER(ah)) { - REG_WRITE(ah, AR_WA, ah->WARegVal); + REG_WRITE(ah, AR_WA(ah), ah->WARegVal); udelay(10); } - REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | + REG_WRITE(ah, AR_RTC_FORCE_WAKE(ah), AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah)) REG_WRITE(ah, AR_RC, AR_RC_AHB); - REG_WRITE(ah, AR_RTC_RESET, 0); + REG_WRITE(ah, AR_RTC_RESET(ah), 0); REGWRITE_BUFFER_FLUSH(ah); - if (!AR_SREV_9300_20_OR_LATER(ah)) - udelay(2); + udelay(2); if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah)) REG_WRITE(ah, AR_RC, 0); - REG_WRITE(ah, AR_RTC_RESET, 1); + REG_WRITE(ah, AR_RTC_RESET(ah), 1); if (!ath9k_hw_wait(ah, - AR_RTC_STATUS, - AR_RTC_STATUS_M, + AR_RTC_STATUS(ah), + AR_RTC_STATUS_M(ah), AR_RTC_STATUS_ON, AH_WAIT_TIMEOUT)) { ath_dbg(ath9k_hw_common(ah), RESET, "RTC not waking up\n"); @@ -1435,11 +1484,11 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) bool ret = false; if (AR_SREV_9300_20_OR_LATER(ah)) { - REG_WRITE(ah, AR_WA, ah->WARegVal); + REG_WRITE(ah, AR_WA(ah), ah->WARegVal); udelay(10); } - REG_WRITE(ah, AR_RTC_FORCE_WAKE, + REG_WRITE(ah, AR_RTC_FORCE_WAKE(ah), AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); if (!ah->reset_power_on) @@ -1473,7 +1522,7 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah, else reset_type = ATH9K_RESET_COLD; } else if (ah->chip_fullsleep || REG_READ(ah, AR_Q_TXE) || - (REG_READ(ah, AR_CR) & AR_CR_RXE)) + (REG_READ(ah, AR_CR) & AR_CR_RXE(ah))) reset_type = ATH9K_RESET_COLD; if (!ath9k_hw_set_reset_reg(ah, reset_type)) @@ -1487,7 +1536,6 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah, if (AR_SREV_9330(ah)) ar9003_hw_internal_regulator_apply(ah); ath9k_hw_init_pll(ah, chan); - ath9k_hw_set_rfmode(ah, chan); return true; } @@ -1496,16 +1544,17 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_capabilities *pCap = &ah->caps; + bool band_switch = false, mode_diff = false; + u8 ini_reloaded = 0; u32 qnum; int r; - bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); - bool band_switch, mode_diff; - u8 ini_reloaded; - band_switch = (chan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ)) != - (ah->curchan->channelFlags & (CHANNEL_2GHZ | - CHANNEL_5GHZ)); - mode_diff = (chan->chanmode != ah->curchan->chanmode); + if (pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) { + u32 flags_diff = chan->channelFlags ^ ah->curchan->channelFlags; + band_switch = !!(flags_diff & CHANNEL_5GHZ); + mode_diff = !!(flags_diff & ~CHANNEL_HT); + } for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { if (ath9k_hw_numtxpending(ah, qnum)) { @@ -1520,11 +1569,12 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, return false; } - if (edma && (band_switch || mode_diff)) { + if (band_switch || mode_diff) { ath9k_hw_mark_phy_inactive(ah); udelay(5); - ath9k_hw_init_pll(ah, NULL); + if (band_switch) + ath9k_hw_init_pll(ah, chan); if (ath9k_hw_fast_chan_change(ah, chan, &ini_reloaded)) { ath_err(common, "Failed to do fast channel change\n"); @@ -1541,22 +1591,19 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, } ath9k_hw_set_clockrate(ah); ath9k_hw_apply_txpower(ah, chan, false); - ath9k_hw_rfbus_done(ah); - - if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) - ath9k_hw_set_delta_slope(ah, chan); + ath9k_hw_set_delta_slope(ah, chan); ath9k_hw_spur_mitigate_freq(ah, chan); - if (edma && (band_switch || mode_diff)) { - ah->ah_flags |= AH_FASTCC; - if (band_switch || ini_reloaded) - ah->eep_ops->set_board_values(ah, chan); + if (band_switch || ini_reloaded) + ah->eep_ops->set_board_values(ah, chan); - ath9k_hw_init_bb(ah, chan); + ath9k_hw_init_bb(ah, chan); + ath9k_hw_rfbus_done(ah); - if (band_switch || ini_reloaded) - ath9k_hw_init_cal(ah, chan); + if (band_switch || ini_reloaded) { + ah->ah_flags |= AH_FASTCC; + ath9k_hw_init_cal(ah, chan); ah->ah_flags &= ~AH_FASTCC; } @@ -1572,85 +1619,33 @@ static void ath9k_hw_apply_gpio_override(struct ath_hw *ah) if (!(gpio_mask & 1)) continue; - ath9k_hw_cfg_output(ah, i, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_gpio_request_out(ah, i, NULL, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i))); } } -static bool ath9k_hw_check_dcs(u32 dma_dbg, u32 num_dcu_states, - int *hang_state, int *hang_pos) -{ - static u32 dcu_chain_state[] = {5, 6, 9}; /* DCU chain stuck states */ - u32 chain_state, dcs_pos, i; - - for (dcs_pos = 0; dcs_pos < num_dcu_states; dcs_pos++) { - chain_state = (dma_dbg >> (5 * dcs_pos)) & 0x1f; - for (i = 0; i < 3; i++) { - if (chain_state == dcu_chain_state[i]) { - *hang_state = chain_state; - *hang_pos = dcs_pos; - return true; - } - } - } - return false; -} - -#define DCU_COMPLETE_STATE 1 -#define DCU_COMPLETE_STATE_MASK 0x3 -#define NUM_STATUS_READS 50 -static bool ath9k_hw_detect_mac_hang(struct ath_hw *ah) +void ath9k_hw_check_nav(struct ath_hw *ah) { - u32 chain_state, comp_state, dcs_reg = AR_DMADBG_4; - u32 i, hang_pos, hang_state, num_state = 6; - - comp_state = REG_READ(ah, AR_DMADBG_6); - - if ((comp_state & DCU_COMPLETE_STATE_MASK) != DCU_COMPLETE_STATE) { - ath_dbg(ath9k_hw_common(ah), RESET, - "MAC Hang signature not found at DCU complete\n"); - return false; - } - - chain_state = REG_READ(ah, dcs_reg); - if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos)) - goto hang_check_iter; - - dcs_reg = AR_DMADBG_5; - num_state = 4; - chain_state = REG_READ(ah, dcs_reg); - if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos)) - goto hang_check_iter; - - ath_dbg(ath9k_hw_common(ah), RESET, - "MAC Hang signature 1 not found\n"); - return false; - -hang_check_iter: - ath_dbg(ath9k_hw_common(ah), RESET, - "DCU registers: chain %08x complete %08x Hang: state %d pos %d\n", - chain_state, comp_state, hang_state, hang_pos); - - for (i = 0; i < NUM_STATUS_READS; i++) { - chain_state = REG_READ(ah, dcs_reg); - chain_state = (chain_state >> (5 * hang_pos)) & 0x1f; - comp_state = REG_READ(ah, AR_DMADBG_6); + struct ath_common *common = ath9k_hw_common(ah); + u32 val; - if (((comp_state & DCU_COMPLETE_STATE_MASK) != - DCU_COMPLETE_STATE) || - (chain_state != hang_state)) - return false; + val = REG_READ(ah, AR_NAV); + if (val != 0xdeadbeef && val > 0x7fff) { + ath_dbg(common, BSTUCK, "Abnormal NAV: 0x%x\n", val); + REG_WRITE(ah, AR_NAV, 0); } - - ath_dbg(ath9k_hw_common(ah), RESET, "MAC Hang signature 1 found\n"); - - return true; } +EXPORT_SYMBOL(ath9k_hw_check_nav); bool ath9k_hw_check_alive(struct ath_hw *ah) { int count = 50; - u32 reg; + u32 reg, last_val; + + /* Check if chip failed to wake up */ + if (REG_READ(ah, AR_CFG) == 0xdeadbeef) + return false; if (AR_SREV_9300(ah)) return !ath9k_hw_detect_mac_hang(ah); @@ -1658,9 +1653,14 @@ bool ath9k_hw_check_alive(struct ath_hw *ah) if (AR_SREV_9285_12_OR_LATER(ah)) return true; + last_val = REG_READ(ah, AR_OBS_BUS_1); do { reg = REG_READ(ah, AR_OBS_BUS_1); + if (reg != last_val) + return true; + udelay(1); + last_val = reg; if ((reg & 0x7E7FFFEF) == 0x00702400) continue; @@ -1686,16 +1686,22 @@ static void ath9k_hw_init_mfp(struct ath_hw *ah) * frames when constructing CCMP AAD. */ REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT, 0xc7ff); - ah->sw_mgmt_crypto = false; + if (AR_SREV_9271(ah) || AR_DEVID_7010(ah)) + ah->sw_mgmt_crypto_tx = true; + else + ah->sw_mgmt_crypto_tx = false; + ah->sw_mgmt_crypto_rx = false; } else if (AR_SREV_9160_10_OR_LATER(ah)) { /* Disable hardware crypto for management frames */ REG_CLR_BIT(ah, AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE); REG_SET_BIT(ah, AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT); - ah->sw_mgmt_crypto = true; + ah->sw_mgmt_crypto_tx = true; + ah->sw_mgmt_crypto_rx = true; } else { - ah->sw_mgmt_crypto = true; + ah->sw_mgmt_crypto_tx = true; + ah->sw_mgmt_crypto_rx = true; } } @@ -1708,7 +1714,6 @@ static void ath9k_hw_reset_opmode(struct ath_hw *ah, REG_RMW(ah, AR_STA_ID1, macStaId1 | AR_STA_ID1_RTS_USE_DEF - | (ah->config.ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0) | ah->sta_id1_defaults, ~AR_STA_ID1_SADH_MASK); ath_hw_setbssidmask(common); @@ -1767,7 +1772,8 @@ static void ath9k_hw_init_desc(struct ath_hw *ah) } #ifdef __BIG_ENDIAN else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) || - AR_SREV_9550(ah)) + AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0); else REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); @@ -1778,16 +1784,11 @@ static void ath9k_hw_init_desc(struct ath_hw *ah) /* * Fast channel change: * (Change synthesizer based on channel freq without resetting chip) - * - * Don't do FCC when - * - Flag is not set - * - Chip is just coming out of full sleep - * - Channel to be set is same as current channel - * - Channel flags are different, (eg.,moving from 2GHz to 5GHz channel) */ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_capabilities *pCap = &ah->caps; int ret; if (AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI) @@ -1806,8 +1807,11 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) (CHANNEL_HALF | CHANNEL_QUARTER)) goto fail; - if ((chan->channelFlags & CHANNEL_ALL) != - (ah->curchan->channelFlags & CHANNEL_ALL)) + /* + * If cross-band fcc is not supoprted, bail out if channelFlags differ. + */ + if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) && + ((chan->channelFlags ^ ah->curchan->channelFlags) & ~CHANNEL_HT)) goto fail; if (!ath9k_hw_check_alive(ah)) @@ -1818,9 +1822,9 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) * re-using are present. */ if (AR_SREV_9462(ah) && (ah->caldata && - (!ah->caldata->done_txiqcal_once || - !ah->caldata->done_txclcal_once || - !ah->caldata->rtt_done))) + (!test_bit(TXIQCAL_DONE, &ah->caldata->cal_flags) || + !test_bit(TXCLCAL_DONE, &ah->caldata->cal_flags) || + !test_bit(RTT_DONE, &ah->caldata->cal_flags)))) goto fail; ath_dbg(common, RESET, "FastChannelChange for %d -> %d\n", @@ -1844,6 +1848,14 @@ fail: return -EINVAL; } +u32 ath9k_hw_get_tsf_offset(ktime_t last, ktime_t cur) +{ + if (cur == 0) + cur = ktime_get_raw(); + return ktime_us_delta(cur, last); +} +EXPORT_SYMBOL(ath9k_hw_get_tsf_offset); + int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, struct ath9k_hw_cal_data *caldata, bool fastcc) { @@ -1851,6 +1863,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, u32 saveLedState; u32 saveDefAntenna; u32 macStaId1; + ktime_t tsf_ts; + u32 tsf_offset; u64 tsf = 0; int r; bool start_mci_reset = false; @@ -1870,15 +1884,14 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ah->caldata = caldata; if (caldata && (chan->channel != caldata->channel || - chan->channelFlags != caldata->channelFlags || - chan->chanmode != caldata->chanmode)) { + chan->channelFlags != caldata->channelFlags)) { /* Operating channel changed, reset channel calibration data */ memset(caldata, 0, sizeof(*caldata)); ath9k_init_nfcal_hist_buffer(ah, chan); } else if (caldata) { - caldata->paprd_packet_sent = false; + clear_bit(PAPRD_PACKET_SENT, &caldata->cal_flags); } - ah->noise = ath9k_hw_getchan_noise(ah, chan); + ah->noise = ath9k_hw_getchan_noise(ah, chan, chan->noisefloor); if (fastcc) { r = ath9k_hw_do_fastcc(ah, chan); @@ -1895,10 +1908,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; - /* For chips on which RTC reset is done, save TSF before it gets cleared */ - if (AR_SREV_9100(ah) || - (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))) - tsf = ath9k_hw_gettsf64(ah); + /* Save TSF before chip reset, a cold reset clears it */ + tsf_ts = ktime_get_raw(); + tsf = ath9k_hw_gettsf64(ah); saveLedState = REG_READ(ah, AR_CFG_LED) & (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | @@ -1931,11 +1943,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, } /* Restore TSF */ - if (tsf) - ath9k_hw_settsf64(ah, tsf); + tsf_offset = ath9k_hw_get_tsf_offset(tsf_ts, 0); + ath9k_hw_settsf64(ah, tsf + tsf_offset); if (AR_SREV_9280_20_OR_LATER(ah)) - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL(ah), AR_GPIO_JTAG_DISABLE); if (!AR_SREV_9300_20_OR_LATER(ah)) ar9002_hw_enable_async_fifo(ah); @@ -1944,25 +1956,24 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (r) return r; + ath9k_hw_set_rfmode(ah, chan); + if (ath9k_hw_mci_is_enabled(ah)) ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep); /* * Some AR91xx SoC devices frequently fail to accept TSF writes * right after the chip reset. When that happens, write a new - * value after the initvals have been applied, with an offset - * based on measured time difference + * value after the initvals have been applied. */ if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) { - tsf += 1500; - ath9k_hw_settsf64(ah, tsf); + tsf_offset = ath9k_hw_get_tsf_offset(tsf_ts, 0); + ath9k_hw_settsf64(ah, tsf + tsf_offset); } ath9k_hw_init_mfp(ah); - if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) - ath9k_hw_set_delta_slope(ah, chan); - + ath9k_hw_set_delta_slope(ah, chan); ath9k_hw_spur_mitigate_freq(ah, chan); ah->eep_ops->set_board_values(ah, chan); @@ -1980,7 +1991,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_init_qos(ah); if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio); + ath9k_hw_gpio_request_in(ah, ah->rfkill_gpio, "ath9k-rfkill"); ath9k_hw_init_global_settings(ah); @@ -1998,23 +2009,25 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_set_dma(ah); if (!ath9k_hw_mci_is_enabled(ah)) - REG_WRITE(ah, AR_OBS, 8); + REG_WRITE(ah, AR_OBS(ah), 8); + ENABLE_REG_RMW_BUFFER(ah); if (ah->config.rx_intr_mitigation) { - REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500); - REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000); + REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, ah->config.rimt_last); + REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, ah->config.rimt_first); } if (ah->config.tx_intr_mitigation) { REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, 300); REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, 750); } + REG_RMW_BUFFER_FLUSH(ah); ath9k_hw_init_bb(ah, chan); if (caldata) { - caldata->done_txiqcal_once = false; - caldata->done_txclcal_once = false; + clear_bit(TXIQCAL_DONE, &caldata->cal_flags); + clear_bit(TXCLCAL_DONE, &caldata->cal_flags); } if (!ath9k_hw_init_cal(ah, chan)) return -EIO; @@ -2029,6 +2042,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REGWRITE_BUFFER_FLUSH(ah); + ath9k_hw_gen_timer_start_tsf2(ah); + ath9k_hw_init_desc(ah); if (ath9k_hw_btcoex_is_enabled(ah)) @@ -2037,19 +2052,28 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (ath9k_hw_mci_is_enabled(ah)) ar9003_mci_check_bt(ah); - ath9k_hw_loadnf(ah, chan); - ath9k_hw_start_nfcal(ah, true); - if (AR_SREV_9300_20_OR_LATER(ah)) { + ath9k_hw_loadnf(ah, chan); + ath9k_hw_start_nfcal(ah, true); + } + + if (AR_SREV_9300_20_OR_LATER(ah)) ar9003_hw_bb_watchdog_config(ah); + + if (ah->config.hw_hang_checks & HW_PHYRESTART_CLC_WAR) ar9003_hw_disable_phy_restart(ah); - } ath9k_hw_apply_gpio_override(ah); - if (AR_SREV_9565(ah) && ah->shared_chain_lnadiv) + if (AR_SREV_9565(ah) && common->bt_ant_diversity) REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON); + if (ah->hw->conf.radar_enabled) { + /* set HW specific DFS configuration */ + ah->radar_conf.ext_channel = IS_CHAN_HT40(chan); + ath9k_hw_set_radar_params(ah); + } + return 0; } EXPORT_SYMBOL(ath9k_hw_reset); @@ -2079,7 +2103,7 @@ static void ath9k_set_power_sleep(struct ath_hw *ah) * Clear the RTC force wake bit to allow the * mac to go to sleep. */ - REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); + REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE(ah), AR_RTC_FORCE_WAKE_EN); if (ath9k_hw_mci_is_enabled(ah)) udelay(100); @@ -2089,13 +2113,13 @@ static void ath9k_set_power_sleep(struct ath_hw *ah) /* Shutdown chip. Active low */ if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) { - REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); + REG_CLR_BIT(ah, AR_RTC_RESET(ah), AR_RTC_RESET_EN); udelay(2); } - /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */ + /* Clear Bit 14 of AR_WA(ah) after putting chip into Full Sleep mode. */ if (AR_SREV_9300_20_OR_LATER(ah)) - REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE); + REG_WRITE(ah, AR_WA(ah), ah->WARegVal & ~AR_WA_D3_L1_DISABLE); } /* @@ -2111,13 +2135,13 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah) if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { /* Set WakeOnInterrupt bit; clear ForceWake bit */ - REG_WRITE(ah, AR_RTC_FORCE_WAKE, + REG_WRITE(ah, AR_RTC_FORCE_WAKE(ah), AR_RTC_FORCE_WAKE_ON_INT); } else { /* When chip goes into network sleep, it could be waken * up by MCI_INT interrupt caused by BT's HW messages - * (LNA_xxx, CONT_xxx) which chould be in a very fast + * (LNA_xxx, CONT_xxx) which could be in a very fast * rate (~100us). This will cause chip to leave and * re-enter network sleep mode frequently, which in * consequence will have WLAN MCI HW to generate lots of @@ -2131,15 +2155,15 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah) * Clear the RTC force wake bit to allow the * mac to go to sleep. */ - REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); + REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE(ah), AR_RTC_FORCE_WAKE_EN); if (ath9k_hw_mci_is_enabled(ah)) udelay(30); } - /* Clear Bit 14 of AR_WA after putting chip into Net Sleep mode. */ + /* Clear Bit 14 of AR_WA(ah) after putting chip into Net Sleep mode. */ if (AR_SREV_9300_20_OR_LATER(ah)) - REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE); + REG_WRITE(ah, AR_WA(ah), ah->WARegVal & ~AR_WA_D3_L1_DISABLE); } static bool ath9k_hw_set_power_awake(struct ath_hw *ah) @@ -2147,14 +2171,14 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah) u32 val; int i; - /* Set Bits 14 and 17 of AR_WA before powering on the chip. */ + /* Set Bits 14 and 17 of AR_WA(ah) before powering on the chip. */ if (AR_SREV_9300_20_OR_LATER(ah)) { - REG_WRITE(ah, AR_WA, ah->WARegVal); + REG_WRITE(ah, AR_WA(ah), ah->WARegVal); udelay(10); } - if ((REG_READ(ah, AR_RTC_STATUS) & - AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { + if ((REG_READ(ah, AR_RTC_STATUS(ah)) & + AR_RTC_STATUS_M(ah)) == AR_RTC_STATUS_SHUTDOWN) { if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { return false; } @@ -2162,19 +2186,22 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah) ath9k_hw_init_pll(ah, NULL); } if (AR_SREV_9100(ah)) - REG_SET_BIT(ah, AR_RTC_RESET, + REG_SET_BIT(ah, AR_RTC_RESET(ah), AR_RTC_RESET_EN); - REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, + REG_SET_BIT(ah, AR_RTC_FORCE_WAKE(ah), AR_RTC_FORCE_WAKE_EN); - udelay(50); + if (AR_SREV_9100(ah)) + mdelay(10); + else + udelay(50); for (i = POWER_UP_TIME / 50; i > 0; i--) { - val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; + val = REG_READ(ah, AR_RTC_STATUS(ah)) & AR_RTC_STATUS_M(ah); if (val == AR_RTC_STATUS_ON) break; udelay(50); - REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, + REG_SET_BIT(ah, AR_RTC_FORCE_WAKE(ah), AR_RTC_FORCE_WAKE_EN); } if (i == 0) { @@ -2256,9 +2283,7 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) case NL80211_IFTYPE_ADHOC: REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); - REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon + - TU_TO_USEC(ah->atim_window ? ah->atim_window : 1)); - flags |= AR_NDP_TIMER_EN; + fallthrough; case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon); @@ -2273,13 +2298,11 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) ath_dbg(ath9k_hw_common(ah), BEACON, "%s: unsupported opmode: %d\n", __func__, ah->opmode); return; - break; } REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period); REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period); REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period); - REG_WRITE(ah, AR_NDP_PERIOD, beacon_period); REGWRITE_BUFFER_FLUSH(ah); @@ -2296,12 +2319,9 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, ENABLE_REGWRITE_BUFFER(ah); - REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt)); - - REG_WRITE(ah, AR_BEACON_PERIOD, - TU_TO_USEC(bs->bs_intval)); - REG_WRITE(ah, AR_DMA_BEACON_PERIOD, - TU_TO_USEC(bs->bs_intval)); + REG_WRITE(ah, AR_NEXT_TBTT_TIMER, bs->bs_nexttbtt); + REG_WRITE(ah, AR_BEACON_PERIOD, bs->bs_intval); + REG_WRITE(ah, AR_DMA_BEACON_PERIOD, bs->bs_intval); REGWRITE_BUFFER_FLUSH(ah); @@ -2322,16 +2342,15 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, else nextTbtt = bs->bs_nexttbtt; - ath_dbg(common, BEACON, "next DTIM %d\n", bs->bs_nextdtim); - ath_dbg(common, BEACON, "next beacon %d\n", nextTbtt); - ath_dbg(common, BEACON, "beacon period %d\n", beaconintval); - ath_dbg(common, BEACON, "DTIM period %d\n", dtimperiod); + ath_dbg(common, BEACON, "next DTIM %u\n", bs->bs_nextdtim); + ath_dbg(common, BEACON, "next beacon %u\n", nextTbtt); + ath_dbg(common, BEACON, "beacon period %u\n", beaconintval); + ath_dbg(common, BEACON, "DTIM period %u\n", dtimperiod); ENABLE_REGWRITE_BUFFER(ah); - REG_WRITE(ah, AR_NEXT_DTIM, - TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); - REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP)); + REG_WRITE(ah, AR_NEXT_DTIM, bs->bs_nextdtim - SLEEP_SLOP); + REG_WRITE(ah, AR_NEXT_TIM, nextTbtt - SLEEP_SLOP); REG_WRITE(ah, AR_SLEEP1, SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT) @@ -2345,8 +2364,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, REG_WRITE(ah, AR_SLEEP2, SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT)); - REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); - REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); + REG_WRITE(ah, AR_TIM_PERIOD, beaconintval); + REG_WRITE(ah, AR_DTIM_PERIOD, dtimperiod); REGWRITE_BUFFER_FLUSH(ah); @@ -2380,7 +2399,7 @@ static u8 fixup_chainmask(u8 chip_chainmask, u8 eeprom_chainmask) * of tests. The testing requirements are going to be documented. Desired * test requirements are documented at: * - * http://wireless.kernel.org/en/users/Drivers/ath9k/dfs + * https://wireless.wiki.kernel.org/en/users/Drivers/ath9k/dfs * * Once a new chipset gets properly tested an individual commit can be used * to document the testing for DFS for that chipset. @@ -2399,12 +2418,66 @@ static bool ath9k_hw_dfs_tested(struct ath_hw *ah) } } +static void ath9k_gpio_cap_init(struct ath_hw *ah) +{ + struct ath9k_hw_capabilities *pCap = &ah->caps; + + if (AR_SREV_9271(ah)) { + pCap->num_gpio_pins = AR9271_NUM_GPIO; + pCap->gpio_mask = AR9271_GPIO_MASK; + } else if (AR_DEVID_7010(ah)) { + pCap->num_gpio_pins = AR7010_NUM_GPIO; + pCap->gpio_mask = AR7010_GPIO_MASK; + } else if (AR_SREV_9287(ah)) { + pCap->num_gpio_pins = AR9287_NUM_GPIO; + pCap->gpio_mask = AR9287_GPIO_MASK; + } else if (AR_SREV_9285(ah)) { + pCap->num_gpio_pins = AR9285_NUM_GPIO; + pCap->gpio_mask = AR9285_GPIO_MASK; + } else if (AR_SREV_9280(ah)) { + pCap->num_gpio_pins = AR9280_NUM_GPIO; + pCap->gpio_mask = AR9280_GPIO_MASK; + } else if (AR_SREV_9300(ah)) { + pCap->num_gpio_pins = AR9300_NUM_GPIO; + pCap->gpio_mask = AR9300_GPIO_MASK; + } else if (AR_SREV_9330(ah)) { + pCap->num_gpio_pins = AR9330_NUM_GPIO; + pCap->gpio_mask = AR9330_GPIO_MASK; + } else if (AR_SREV_9340(ah)) { + pCap->num_gpio_pins = AR9340_NUM_GPIO; + pCap->gpio_mask = AR9340_GPIO_MASK; + } else if (AR_SREV_9462(ah)) { + pCap->num_gpio_pins = AR9462_NUM_GPIO; + pCap->gpio_mask = AR9462_GPIO_MASK; + } else if (AR_SREV_9485(ah)) { + pCap->num_gpio_pins = AR9485_NUM_GPIO; + pCap->gpio_mask = AR9485_GPIO_MASK; + } else if (AR_SREV_9531(ah)) { + pCap->num_gpio_pins = AR9531_NUM_GPIO; + pCap->gpio_mask = AR9531_GPIO_MASK; + } else if (AR_SREV_9550(ah)) { + pCap->num_gpio_pins = AR9550_NUM_GPIO; + pCap->gpio_mask = AR9550_GPIO_MASK; + } else if (AR_SREV_9561(ah)) { + pCap->num_gpio_pins = AR9561_NUM_GPIO; + pCap->gpio_mask = AR9561_GPIO_MASK; + } else if (AR_SREV_9565(ah)) { + pCap->num_gpio_pins = AR9565_NUM_GPIO; + pCap->gpio_mask = AR9565_GPIO_MASK; + } else if (AR_SREV_9580(ah)) { + pCap->num_gpio_pins = AR9580_NUM_GPIO; + pCap->gpio_mask = AR9580_GPIO_MASK; + } else { + pCap->num_gpio_pins = AR_NUM_GPIO; + pCap->gpio_mask = AR_GPIO_MASK; + } +} + int ath9k_hw_fill_cap_info(struct ath_hw *ah) { struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath_common *common = ath9k_hw_common(ah); - unsigned int chip_chainmask; u16 eeval; u8 ant_div_ctl1, tx_chainmask, rx_chainmask; @@ -2424,35 +2497,46 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) } eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE); - if ((eeval & (AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A)) == 0) { - ath_err(common, - "no band has been marked as supported in EEPROM\n"); - return -EINVAL; + + if (eeval & AR5416_OPFLAGS_11A) { + if (ah->disable_5ghz) + ath_warn(common, "disabling 5GHz band\n"); + else + pCap->hw_caps |= ATH9K_HW_CAP_5GHZ; } - if (eeval & AR5416_OPFLAGS_11A) - pCap->hw_caps |= ATH9K_HW_CAP_5GHZ; + if (eeval & AR5416_OPFLAGS_11G) { + if (ah->disable_2ghz) + ath_warn(common, "disabling 2GHz band\n"); + else + pCap->hw_caps |= ATH9K_HW_CAP_2GHZ; + } - if (eeval & AR5416_OPFLAGS_11G) - pCap->hw_caps |= ATH9K_HW_CAP_2GHZ; + if ((pCap->hw_caps & (ATH9K_HW_CAP_2GHZ | ATH9K_HW_CAP_5GHZ)) == 0) { + ath_err(common, "both bands are disabled\n"); + return -EINVAL; + } + + ath9k_gpio_cap_init(ah); if (AR_SREV_9485(ah) || AR_SREV_9285(ah) || AR_SREV_9330(ah) || AR_SREV_9565(ah)) - chip_chainmask = 1; - else if (AR_SREV_9462(ah)) - chip_chainmask = 3; + pCap->chip_chainmask = 1; else if (!AR_SREV_9280_20_OR_LATER(ah)) - chip_chainmask = 7; - else if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9340(ah)) - chip_chainmask = 3; + pCap->chip_chainmask = 7; + else if (!AR_SREV_9300_20_OR_LATER(ah) || + AR_SREV_9340(ah) || + AR_SREV_9462(ah) || + AR_SREV_9531(ah)) + pCap->chip_chainmask = 3; else - chip_chainmask = 7; + pCap->chip_chainmask = 7; pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK); /* - * For AR9271 we will temporarilly uses the rx chainmax as read from + * For AR9271 we will temporarily use the rx chainmax as read from * the EEPROM. */ if ((ah->hw_version.devid == AR5416_DEVID_PCI) && @@ -2466,8 +2550,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) /* Use rx_chainmask from EEPROM. */ pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); - pCap->tx_chainmask = fixup_chainmask(chip_chainmask, pCap->tx_chainmask); - pCap->rx_chainmask = fixup_chainmask(chip_chainmask, pCap->rx_chainmask); + pCap->tx_chainmask = fixup_chainmask(pCap->chip_chainmask, pCap->tx_chainmask); + pCap->rx_chainmask = fixup_chainmask(pCap->chip_chainmask, pCap->rx_chainmask); ah->txchainmask = pCap->tx_chainmask; ah->rxchainmask = pCap->rx_chainmask; @@ -2484,27 +2568,12 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->hw_caps &= ~ATH9K_HW_CAP_HT; - if (AR_SREV_9271(ah)) - pCap->num_gpio_pins = AR9271_NUM_GPIO; - else if (AR_DEVID_7010(ah)) - pCap->num_gpio_pins = AR7010_NUM_GPIO; - else if (AR_SREV_9300_20_OR_LATER(ah)) - pCap->num_gpio_pins = AR9300_NUM_GPIO; - else if (AR_SREV_9287_11_OR_LATER(ah)) - pCap->num_gpio_pins = AR9287_NUM_GPIO; - else if (AR_SREV_9285_12_OR_LATER(ah)) - pCap->num_gpio_pins = AR9285_NUM_GPIO; - else if (AR_SREV_9280_20_OR_LATER(ah)) - pCap->num_gpio_pins = AR928X_NUM_GPIO; - else - pCap->num_gpio_pins = AR_NUM_GPIO; - if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX; else pCap->rts_aggr_limit = (8 * 1024); -#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) +#ifdef CONFIG_ATH9K_RFKILL ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT); if (ah->rfsilent & EEP_RFSILENT_ENABLED) { ah->rfkill_gpio = @@ -2527,7 +2596,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9300_20_OR_LATER(ah)) { pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_FASTCLOCK; - if (!AR_SREV_9330(ah) && !AR_SREV_9485(ah) && !AR_SREV_9565(ah)) + if (!AR_SREV_9330(ah) && !AR_SREV_9485(ah) && + !AR_SREV_9561(ah) && !AR_SREV_9565(ah)) pCap->hw_caps |= ATH9K_HW_CAP_LDPC; pCap->rx_hp_qdepth = ATH9K_HW_RX_HP_QDEPTH; @@ -2544,40 +2614,36 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) if (AR_SREV_9300_20_OR_LATER(ah)) pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED; - if (AR_SREV_9300_20_OR_LATER(ah)) + if (AR_SREV_9561(ah)) + ah->ent_mode = 0x3BDA000; + else if (AR_SREV_9300_20_OR_LATER(ah)) ah->ent_mode = REG_READ(ah, AR_ENT_OTP); if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah)) pCap->hw_caps |= ATH9K_HW_CAP_SGI_20; - if (AR_SREV_9285(ah)) + if (AR_SREV_9285(ah)) { if (ah->eep_ops->get_eeprom(ah, EEP_MODAL_VER) >= 3) { ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); - if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1)) + if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1)) { pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB; + ath_info(common, "Enable LNA combining\n"); + } } + } + if (AR_SREV_9300_20_OR_LATER(ah)) { if (ah->eep_ops->get_eeprom(ah, EEP_CHAIN_MASK_REDUCE)) pCap->hw_caps |= ATH9K_HW_CAP_APM; } - if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) { ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1); - /* - * enable the diversity-combining algorithm only when - * both enable_lna_div and enable_fast_div are set - * Table for Diversity - * ant_div_alt_lnaconf bit 0-1 - * ant_div_main_lnaconf bit 2-3 - * ant_div_alt_gaintb bit 4 - * ant_div_main_gaintb bit 5 - * enable_ant_div_lnadiv bit 6 - * enable_ant_fast_div bit 7 - */ - if ((ant_div_ctl1 >> 0x6) == 0x3) + if ((ant_div_ctl1 >> 0x6) == 0x3) { pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB; + ath_info(common, "Enable LNA combining\n"); + } } if (ath9k_hw_dfs_tested(ah)) @@ -2603,13 +2669,17 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->hw_caps |= ATH9K_HW_CAP_RTT; } - if (AR_SREV_9462(ah)) - pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE; - if (AR_SREV_9300_20_OR_LATER(ah) && ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) pCap->hw_caps |= ATH9K_HW_CAP_PAPRD; +#ifdef CONFIG_ATH9K_WOW + if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565_11_OR_LATER(ah)) + ah->wow.max_patterns = MAX_NUM_PATTERN; + else + ah->wow.max_patterns = MAX_NUM_PATTERN_LEGACY; +#endif + return 0; } @@ -2617,23 +2687,22 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) /* GPIO / RFKILL / Antennae */ /****************************/ -static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah, - u32 gpio, u32 type) +static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah, u32 gpio, u32 type) { int addr; u32 gpio_shift, tmp; if (gpio > 11) - addr = AR_GPIO_OUTPUT_MUX3; + addr = AR_GPIO_OUTPUT_MUX3(ah); else if (gpio > 5) - addr = AR_GPIO_OUTPUT_MUX2; + addr = AR_GPIO_OUTPUT_MUX2(ah); else - addr = AR_GPIO_OUTPUT_MUX1; + addr = AR_GPIO_OUTPUT_MUX1(ah); gpio_shift = (gpio % 6) * 5; - if (AR_SREV_9280_20_OR_LATER(ah) - || (addr != AR_GPIO_OUTPUT_MUX1)) { + if (AR_SREV_9280_20_OR_LATER(ah) || + (addr != AR_GPIO_OUTPUT_MUX1(ah))) { REG_RMW(ah, addr, (type << gpio_shift), (0x1f << gpio_shift)); } else { @@ -2645,92 +2714,143 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah, } } -void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio) +/* BSP should set the corresponding MUX register correctly. + */ +static void ath9k_hw_gpio_cfg_soc(struct ath_hw *ah, u32 gpio, bool out, + const char *label) { - u32 gpio_shift; + int err; - BUG_ON(gpio >= ah->caps.num_gpio_pins); + if (ah->caps.gpio_requested & BIT(gpio)) + return; - if (AR_DEVID_7010(ah)) { - gpio_shift = gpio; - REG_RMW(ah, AR7010_GPIO_OE, - (AR7010_GPIO_OE_AS_INPUT << gpio_shift), - (AR7010_GPIO_OE_MASK << gpio_shift)); + err = devm_gpio_request_one(ah->dev, gpio, out ? GPIOF_OUT_INIT_LOW : GPIOF_IN, label); + if (err) { + ath_err(ath9k_hw_common(ah), "request GPIO%d failed:%d\n", + gpio, err); return; } - gpio_shift = gpio << 1; - REG_RMW(ah, - AR_GPIO_OE_OUT, - (AR_GPIO_OE_OUT_DRV_NO << gpio_shift), - (AR_GPIO_OE_OUT_DRV << gpio_shift)); + ah->caps.gpio_requested |= BIT(gpio); } -EXPORT_SYMBOL(ath9k_hw_cfg_gpio_input); -u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) +static void ath9k_hw_gpio_cfg_wmac(struct ath_hw *ah, u32 gpio, bool out, + u32 ah_signal_type) { -#define MS_REG_READ(x, y) \ - (MS(REG_READ(ah, AR_GPIO_IN_OUT), x##_GPIO_IN_VAL) & (AR_GPIO_BIT(y))) - - if (gpio >= ah->caps.num_gpio_pins) - return 0xffffffff; + u32 gpio_set, gpio_shift = gpio; if (AR_DEVID_7010(ah)) { - u32 val; - val = REG_READ(ah, AR7010_GPIO_IN); - return (MS(val, AR7010_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) == 0; - } else if (AR_SREV_9300_20_OR_LATER(ah)) - return (MS(REG_READ(ah, AR_GPIO_IN), AR9300_GPIO_IN_VAL) & - AR_GPIO_BIT(gpio)) != 0; - else if (AR_SREV_9271(ah)) - return MS_REG_READ(AR9271, gpio) != 0; - else if (AR_SREV_9287_11_OR_LATER(ah)) - return MS_REG_READ(AR9287, gpio) != 0; - else if (AR_SREV_9285_12_OR_LATER(ah)) - return MS_REG_READ(AR9285, gpio) != 0; - else if (AR_SREV_9280_20_OR_LATER(ah)) - return MS_REG_READ(AR928X, gpio) != 0; + gpio_set = out ? + AR7010_GPIO_OE_AS_OUTPUT : AR7010_GPIO_OE_AS_INPUT; + REG_RMW(ah, AR7010_GPIO_OE, gpio_set << gpio_shift, + AR7010_GPIO_OE_MASK << gpio_shift); + } else if (AR_SREV_SOC(ah)) { + gpio_set = out ? 1 : 0; + REG_RMW(ah, AR_GPIO_OE_OUT(ah), gpio_set << gpio_shift, + gpio_set << gpio_shift); + } else { + gpio_shift = gpio << 1; + gpio_set = out ? + AR_GPIO_OE_OUT_DRV_ALL : AR_GPIO_OE_OUT_DRV_NO; + REG_RMW(ah, AR_GPIO_OE_OUT(ah), gpio_set << gpio_shift, + AR_GPIO_OE_OUT_DRV << gpio_shift); + + if (out) + ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); + } +} + +static void ath9k_hw_gpio_request(struct ath_hw *ah, u32 gpio, bool out, + const char *label, u32 ah_signal_type) +{ + WARN_ON(gpio >= ah->caps.num_gpio_pins); + + if (BIT(gpio) & ah->caps.gpio_mask) + ath9k_hw_gpio_cfg_wmac(ah, gpio, out, ah_signal_type); + else if (AR_SREV_SOC(ah)) + ath9k_hw_gpio_cfg_soc(ah, gpio, out, label); else - return MS_REG_READ(AR, gpio) != 0; + WARN_ON(1); } -EXPORT_SYMBOL(ath9k_hw_gpio_get); -void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, - u32 ah_signal_type) +void ath9k_hw_gpio_request_in(struct ath_hw *ah, u32 gpio, const char *label) { - u32 gpio_shift; + ath9k_hw_gpio_request(ah, gpio, false, label, 0); +} +EXPORT_SYMBOL(ath9k_hw_gpio_request_in); - if (AR_DEVID_7010(ah)) { - gpio_shift = gpio; - REG_RMW(ah, AR7010_GPIO_OE, - (AR7010_GPIO_OE_AS_OUTPUT << gpio_shift), - (AR7010_GPIO_OE_MASK << gpio_shift)); +void ath9k_hw_gpio_request_out(struct ath_hw *ah, u32 gpio, const char *label, + u32 ah_signal_type) +{ + ath9k_hw_gpio_request(ah, gpio, true, label, ah_signal_type); +} +EXPORT_SYMBOL(ath9k_hw_gpio_request_out); + +void ath9k_hw_gpio_free(struct ath_hw *ah, u32 gpio) +{ + if (!AR_SREV_SOC(ah)) return; + + WARN_ON(gpio >= ah->caps.num_gpio_pins); + + if (ah->caps.gpio_requested & BIT(gpio)) + ah->caps.gpio_requested &= ~BIT(gpio); +} +EXPORT_SYMBOL(ath9k_hw_gpio_free); + +u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) +{ + u32 val = 0xffffffff; + +#define MS_REG_READ(x, y) \ + (MS(REG_READ(ah, AR_GPIO_IN_OUT(ah)), x##_GPIO_IN_VAL) & BIT(y)) + + WARN_ON(gpio >= ah->caps.num_gpio_pins); + + if (BIT(gpio) & ah->caps.gpio_mask) { + if (AR_SREV_9271(ah)) + val = MS_REG_READ(AR9271, gpio); + else if (AR_SREV_9287(ah)) + val = MS_REG_READ(AR9287, gpio); + else if (AR_SREV_9285(ah)) + val = MS_REG_READ(AR9285, gpio); + else if (AR_SREV_9280(ah)) + val = MS_REG_READ(AR928X, gpio); + else if (AR_DEVID_7010(ah)) + val = REG_READ(ah, AR7010_GPIO_IN) & BIT(gpio); + else if (AR_SREV_9300_20_OR_LATER(ah)) + val = REG_READ(ah, AR_GPIO_IN(ah)) & BIT(gpio); + else + val = MS_REG_READ(AR, gpio); + } else if (BIT(gpio) & ah->caps.gpio_requested) { + val = gpio_get_value(gpio) & BIT(gpio); + } else { + WARN_ON(1); } - ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); - gpio_shift = 2 * gpio; - REG_RMW(ah, - AR_GPIO_OE_OUT, - (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), - (AR_GPIO_OE_OUT_DRV << gpio_shift)); + return !!val; } -EXPORT_SYMBOL(ath9k_hw_cfg_output); +EXPORT_SYMBOL(ath9k_hw_gpio_get); void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) { - if (AR_DEVID_7010(ah)) { - val = val ? 0 : 1; - REG_RMW(ah, AR7010_GPIO_OUT, ((val&1) << gpio), - AR_GPIO_BIT(gpio)); - return; - } + WARN_ON(gpio >= ah->caps.num_gpio_pins); - if (AR_SREV_9271(ah)) - val = ~val; + if (AR_DEVID_7010(ah) || AR_SREV_9271(ah)) + val = !val; + else + val = !!val; + + if (BIT(gpio) & ah->caps.gpio_mask) { + u32 out_addr = AR_DEVID_7010(ah) ? + AR7010_GPIO_OUT : AR_GPIO_IN_OUT(ah); - REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), - AR_GPIO_BIT(gpio)); + REG_RMW(ah, out_addr, val << gpio, BIT(gpio)); + } else if (BIT(gpio) & ah->caps.gpio_requested) { + gpio_set_value(gpio, val); + } else { + WARN_ON(1); + } } EXPORT_SYMBOL(ath9k_hw_set_gpio); @@ -2764,9 +2884,6 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) ENABLE_REGWRITE_BUFFER(ah); - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) - bits |= ATH9K_RX_FILTER_CONTROL_WRAPPER; - REG_WRITE(ah, AR_RX_FILTER, bits); phybits = 0; @@ -2829,24 +2946,21 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan, { struct ath_regulatory *reg = ath9k_hw_regulatory(ah); struct ieee80211_channel *channel; - int chan_pwr, new_pwr, max_gain; - int ant_gain, ant_reduction = 0; + int chan_pwr, new_pwr; + u16 ctl = NO_CTL; if (!chan) return; + if (!test) + ctl = ath9k_regd_get_ctl(reg, chan); + channel = chan->chan; - chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER); + chan_pwr = min_t(int, channel->max_power * 2, MAX_COMBINED_POWER); new_pwr = min_t(int, chan_pwr, reg->power_limit); - max_gain = chan_pwr - new_pwr + channel->max_antenna_gain * 2; - ant_gain = get_antenna_gain(ah, chan); - if (ant_gain > max_gain) - ant_reduction = ant_gain - max_gain; - - ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(reg, chan), - ant_reduction, new_pwr, test); + ah->eep_ops->set_txpower(ah, chan, ctl, + get_antenna_gain(ah, chan), new_pwr, test); } void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test) @@ -2855,9 +2969,9 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test) struct ath9k_channel *chan = ah->curchan; struct ieee80211_channel *channel = chan->chan; - reg->power_limit = min_t(u32, limit, MAX_RATE_POWER); + reg->power_limit = min_t(u32, limit, MAX_COMBINED_POWER); if (test) - channel->max_power = MAX_RATE_POWER / 2; + channel->max_power = MAX_COMBINED_POWER / 2; ath9k_hw_apply_txpower(ah, chan, test); @@ -2938,12 +3052,11 @@ void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set) } EXPORT_SYMBOL(ath9k_hw_set_tsfadjust); -void ath9k_hw_set11nmac2040(struct ath_hw *ah) +void ath9k_hw_set11nmac2040(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; u32 macmode; - if (conf_is_ht40(conf) && !ah->config.cwm_ignore_extcca) + if (IS_CHAN_HT40(chan) && !ah->config.cwm_ignore_extcca) macmode = AR_2040_JOINED_RX_CLEAR; else macmode = 0; @@ -2982,26 +3095,22 @@ static const struct ath_gen_timer_configuration gen_tmr_configuration[] = /* HW generic timer primitives */ -/* compute and clear index of rightmost 1 */ -static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask) -{ - u32 b; - - b = *mask; - b &= (0-b); - *mask &= ~b; - b *= debruijn32; - b >>= 27; - - return timer_table->gen_timer_index[b]; -} - u32 ath9k_hw_gettsf32(struct ath_hw *ah) { return REG_READ(ah, AR_TSF_L32); } EXPORT_SYMBOL(ath9k_hw_gettsf32); +void ath9k_hw_gen_timer_start_tsf2(struct ath_hw *ah) +{ + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + + if (timer_table->tsf2_enabled) { + REG_SET_BIT(ah, AR_DIRECT_CONNECT, AR_DC_AP_STA_EN); + REG_SET_BIT(ah, AR_RESET_TSF, AR_RESET_TSF2_ONCE); + } +} + struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, void (*trigger)(void *), void (*overflow)(void *), @@ -3011,6 +3120,14 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; struct ath_gen_timer *timer; + if ((timer_index < AR_FIRST_NDP_TIMER) || + (timer_index >= ATH_MAX_GEN_TIMER)) + return NULL; + + if ((timer_index > AR_FIRST_NDP_TIMER) && + !AR_SREV_9300_20_OR_LATER(ah)) + return NULL; + timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL); if (timer == NULL) return NULL; @@ -3022,29 +3139,24 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, timer->overflow = overflow; timer->arg = arg; + if ((timer_index > AR_FIRST_NDP_TIMER) && !timer_table->tsf2_enabled) { + timer_table->tsf2_enabled = true; + ath9k_hw_gen_timer_start_tsf2(ah); + } + return timer; } EXPORT_SYMBOL(ath_gen_timer_alloc); void ath9k_hw_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, - u32 trig_timeout, + u32 timer_next, u32 timer_period) { struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; - u32 tsf, timer_next; - - BUG_ON(!timer_period); - - set_bit(timer->index, &timer_table->timer_mask.timer_bits); - - tsf = ath9k_hw_gettsf32(ah); + u32 mask = 0; - timer_next = tsf + trig_timeout; - - ath_dbg(ath9k_hw_common(ah), BTCOEX, - "current tsf %x period %x timer_next %x\n", - tsf, timer_period, timer_next); + timer_table->timer_mask |= BIT(timer->index); /* * Program generic timer registers @@ -3070,10 +3182,19 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah, (1 << timer->index)); } - /* Enable both trigger and thresh interrupt masks */ - REG_SET_BIT(ah, AR_IMR_S5, - (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) | - SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); + if (timer->trigger) + mask |= SM(AR_GENTMR_BIT(timer->index), + AR_IMR_S5_GENTIMER_TRIG); + if (timer->overflow) + mask |= SM(AR_GENTMR_BIT(timer->index), + AR_IMR_S5_GENTIMER_THRESH); + + REG_SET_BIT(ah, AR_IMR_S5, mask); + + if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { + ah->imask |= ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah); + } } EXPORT_SYMBOL(ath9k_hw_gen_timer_start); @@ -3081,11 +3202,6 @@ void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) { struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; - if ((timer->index < AR_FIRST_NDP_TIMER) || - (timer->index >= ATH_MAX_GEN_TIMER)) { - return; - } - /* Clear generic timer enable bits. */ REG_CLR_BIT(ah, gen_tmr_configuration[timer->index].mode_addr, gen_tmr_configuration[timer->index].mode_mask); @@ -3105,7 +3221,12 @@ void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) | SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG))); - clear_bit(timer->index, &timer_table->timer_mask.timer_bits); + timer_table->timer_mask &= ~BIT(timer->index); + + if (timer_table->timer_mask == 0) { + ah->imask &= ~ATH9K_INT_GENTIMER; + ath9k_hw_set_interrupts(ah); + } } EXPORT_SYMBOL(ath9k_hw_gen_timer_stop); @@ -3126,32 +3247,32 @@ void ath_gen_timer_isr(struct ath_hw *ah) { struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; struct ath_gen_timer *timer; - struct ath_common *common = ath9k_hw_common(ah); - u32 trigger_mask, thresh_mask, index; + unsigned long trigger_mask, thresh_mask; + unsigned int index; /* get hardware generic timer interrupt status */ trigger_mask = ah->intr_gen_timer_trigger; thresh_mask = ah->intr_gen_timer_thresh; - trigger_mask &= timer_table->timer_mask.val; - thresh_mask &= timer_table->timer_mask.val; - - trigger_mask &= ~thresh_mask; + trigger_mask &= timer_table->timer_mask; + thresh_mask &= timer_table->timer_mask; - while (thresh_mask) { - index = rightmost_index(timer_table, &thresh_mask); + for_each_set_bit(index, &thresh_mask, ARRAY_SIZE(timer_table->timers)) { timer = timer_table->timers[index]; - BUG_ON(!timer); - ath_dbg(common, BTCOEX, "TSF overflow for Gen timer %d\n", - index); + if (!timer) + continue; + if (!timer->overflow) + continue; + + trigger_mask &= ~BIT(index); timer->overflow(timer->arg); } - while (trigger_mask) { - index = rightmost_index(timer_table, &trigger_mask); + for_each_set_bit(index, &trigger_mask, ARRAY_SIZE(timer_table->timers)) { timer = timer_table->timers[index]; - BUG_ON(!timer); - ath_dbg(common, BTCOEX, - "Gen timer[%d] trigger\n", index); + if (!timer) + continue; + if (!timer->trigger) + continue; timer->trigger(timer->arg); } } @@ -3182,6 +3303,8 @@ static struct { { AR_SREV_VERSION_9462, "9462" }, { AR_SREV_VERSION_9550, "9550" }, { AR_SREV_VERSION_9565, "9565" }, + { AR_SREV_VERSION_9531, "9531" }, + { AR_SREV_VERSION_9561, "9561" }, }; /* For devices with external radios */ @@ -3235,19 +3358,19 @@ void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len) /* chipsets >= AR9280 are single-chip */ if (AR_SREV_9280_20_OR_LATER(ah)) { - used = snprintf(hw_name, len, - "Atheros AR%s Rev:%x", - ath9k_hw_mac_bb_name(ah->hw_version.macVersion), - ah->hw_version.macRev); + used = scnprintf(hw_name, len, + "Atheros AR%s Rev:%x", + ath9k_hw_mac_bb_name(ah->hw_version.macVersion), + ah->hw_version.macRev); } else { - used = snprintf(hw_name, len, - "Atheros AR%s MAC/BB Rev:%x AR%s RF Rev:%x", - ath9k_hw_mac_bb_name(ah->hw_version.macVersion), - ah->hw_version.macRev, - ath9k_hw_rf_name((ah->hw_version.analog5GhzRev & - AR_RADIO_SREV_MAJOR)), - ah->hw_version.phyRev); + used = scnprintf(hw_name, len, + "Atheros AR%s MAC/BB Rev:%x AR%s RF Rev:%x", + ath9k_hw_mac_bb_name(ah->hw_version.macVersion), + ah->hw_version.macRev, + ath9k_hw_rf_name((ah->hw_version.analog5GhzRev + & AR_RADIO_SREV_MAJOR)), + ah->hw_version.phyRev); } hw_name[used] = '\0'; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index cd74b3afef7d..eaa07d6dbde0 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -27,8 +27,10 @@ #include "eeprom.h" #include "calib.h" #include "reg.h" +#include "reg_mci.h" #include "phy.h" #include "btcoex.h" +#include "dynack.h" #include "../regd.h" @@ -52,6 +54,8 @@ #define AR9300_DEVID_QCA955X 0x0038 #define AR9485_DEVID_AR1111 0x0037 #define AR9300_DEVID_AR9565 0x0036 +#define AR9300_DEVID_AR953X 0x003d +#define AR9300_DEVID_QCA956X 0x003f #define AR5416_AR9100_DEVID 0x000b @@ -96,10 +100,22 @@ (_ah)->reg_ops.write_flush((_ah)); \ } while (0) +#define ENABLE_REG_RMW_BUFFER(_ah) \ + do { \ + if ((_ah)->reg_ops.enable_rmw_buffer) \ + (_ah)->reg_ops.enable_rmw_buffer((_ah)); \ + } while (0) + +#define REG_RMW_BUFFER_FLUSH(_ah) \ + do { \ + if ((_ah)->reg_ops.rmw_flush) \ + (_ah)->reg_ops.rmw_flush((_ah)); \ + } while (0) + #define PR_EEP(_s, _val) \ do { \ - len += snprintf(buf + len, size - len, "%20s : %10d\n", \ - _s, (_val)); \ + len += scnprintf(buf + len, size - len, "%20s : %10d\n",\ + _s, (_val)); \ } while (0) #define SM(_v, _f) (((_v) << _f##_S) & _f) @@ -122,6 +138,8 @@ #define REG_WRITE_ARRAY(iniarray, column, regWr) \ ath9k_hw_write_array(ah, iniarray, column, &(regWr)) +#define REG_READ_ARRAY(ah, array, size) \ + ath9k_hw_read_array(ah, array, size) #define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 #define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 @@ -142,7 +160,6 @@ #define AR_GPIO_OUTPUT_MUX_AS_RUCKUS_DATA 0x1e #define AR_GPIOD_MASK 0x00001FFF -#define AR_GPIO_BIT(_gpio) (1 << (_gpio)) #define BASE_ACTIVATE_DELAY 100 #define RTC_PLL_SETTLE_DELAY (AR_SREV_9340(ah) ? 1000 : 100) @@ -156,6 +173,7 @@ #define ATH9K_NUM_QUEUES 10 #define MAX_RATE_POWER 63 +#define MAX_COMBINED_POWER 254 /* 128 dBm, chosen to fit in u8 */ #define AH_WAIT_TIMEOUT 100000 /* (us) */ #define AH_TSF_WRITE_TIMEOUT 100 /* (us) */ #define AH_TIME_QUANTUM 10 @@ -168,7 +186,7 @@ #define CAB_TIMEOUT_VAL 10 #define BEACON_TIMEOUT_VAL 10 #define MIN_BEACON_TIMEOUT_VAL 1 -#define SLEEP_SLOP 3 +#define SLEEP_SLOP TU_TO_USEC(3) #define INIT_CONFIG_STATUS 0x00000000 #define INIT_RSSI_THR 0x00000700 @@ -196,12 +214,13 @@ #define KAL_NUM_DESC_WORDS 12 #define KAL_ANTENNA_MODE 1 #define KAL_TO_DS 1 -#define KAL_DELAY 4 /*delay of 4ms between 2 KAL frames */ +#define KAL_DELAY 4 /* delay of 4ms between 2 KAL frames */ #define KAL_TIMEOUT 900 #define MAX_PATTERN_SIZE 256 #define MAX_PATTERN_MASK_SIZE 32 -#define MAX_NUM_PATTERN 8 +#define MAX_NUM_PATTERN 16 +#define MAX_NUM_PATTERN_LEGACY 8 #define MAX_NUM_USER_PATTERN 6 /* deducting the disassociate and deauthenticate packets */ @@ -215,8 +234,8 @@ #define AH_WOW_BEACON_MISS BIT(3) enum ath_hw_txq_subtype { - ATH_TXQ_AC_BE = 0, - ATH_TXQ_AC_BK = 1, + ATH_TXQ_AC_BK = 0, + ATH_TXQ_AC_BE = 1, ATH_TXQ_AC_VI = 2, ATH_TXQ_AC_VO = 3, }; @@ -242,11 +261,18 @@ enum ath9k_hw_caps { ATH9K_HW_CAP_2GHZ = BIT(11), ATH9K_HW_CAP_5GHZ = BIT(12), ATH9K_HW_CAP_APM = BIT(13), +#ifdef CONFIG_ATH9K_PCOEM ATH9K_HW_CAP_RTT = BIT(14), ATH9K_HW_CAP_MCI = BIT(15), - ATH9K_HW_CAP_DFS = BIT(16), - ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17), - ATH9K_HW_CAP_PAPRD = BIT(18), + ATH9K_HW_CAP_BT_ANT_DIV = BIT(17), +#else + ATH9K_HW_CAP_RTT = 0, + ATH9K_HW_CAP_MCI = 0, + ATH9K_HW_CAP_BT_ANT_DIV = 0, +#endif + ATH9K_HW_CAP_DFS = BIT(18), + ATH9K_HW_CAP_PAPRD = BIT(19), + ATH9K_HW_CAP_FCC_BAND_SWITCH = BIT(20), }; /* @@ -256,18 +282,27 @@ enum ath9k_hw_caps { * an exact user defined pattern or de-authentication/disassoc pattern. * @ATH9K_HW_WOW_PATTERN_MATCH_DWORD: device requires the first four * bytes of the pattern for user defined pattern, de-authentication and - * disassociation patterns for all types of possible frames recieved + * disassociation patterns for all types of possible frames received * of those types. */ +struct ath9k_hw_wow { + u32 wow_event_mask; + u32 wow_event_mask2; + u8 max_patterns; +}; + struct ath9k_hw_capabilities { u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ u16 rts_aggr_limit; u8 tx_chainmask; u8 rx_chainmask; + u8 chip_chainmask; u8 max_txchains; u8 max_rxchains; u8 num_gpio_pins; + u32 gpio_mask; + u32 gpio_requested; u8 rx_hp_qdepth; u8 rx_lp_qdepth; u8 rx_status_len; @@ -275,42 +310,56 @@ struct ath9k_hw_capabilities { u8 txs_len; }; +#define AR_NO_SPUR 0x8000 +#define AR_BASE_FREQ_2GHZ 2300 +#define AR_BASE_FREQ_5GHZ 4900 +#define AR_SPUR_FEEQ_BOUND_HT40 19 +#define AR_SPUR_FEEQ_BOUND_HT20 10 + +enum ath9k_hw_hang_checks { + HW_BB_WATCHDOG = BIT(0), + HW_PHYRESTART_CLC_WAR = BIT(1), + HW_BB_RIFS_HANG = BIT(2), + HW_BB_DFS_HANG = BIT(3), + HW_BB_RX_CLEAR_STUCK_HANG = BIT(4), + HW_MAC_HANG = BIT(5), +}; + +#define AR_PCIE_PLL_PWRSAVE_CONTROL BIT(0) +#define AR_PCIE_PLL_PWRSAVE_ON_D3 BIT(1) +#define AR_PCIE_PLL_PWRSAVE_ON_D0 BIT(2) +#define AR_PCIE_CDR_PWRSAVE_ON_D3 BIT(3) +#define AR_PCIE_CDR_PWRSAVE_ON_D0 BIT(4) + struct ath9k_ops_config { int dma_beacon_response_time; int sw_beacon_response_time; - int additional_swba_backoff; - int ack_6mb; - u32 cwm_ignore_extcca; - bool pcieSerDesWrite; - u8 pcie_clock_req; + bool cwm_ignore_extcca; u32 pcie_waen; u8 analog_shiftreg; u32 ofdm_trig_low; u32 ofdm_trig_high; u32 cck_trig_high; u32 cck_trig_low; - u32 enable_paprd; + bool enable_paprd; int serialize_regmode; bool rx_intr_mitigation; bool tx_intr_mitigation; -#define SPUR_DISABLE 0 -#define SPUR_ENABLE_IOCTL 1 -#define SPUR_ENABLE_EEPROM 2 -#define AR_SPUR_5413_1 1640 -#define AR_SPUR_5413_2 1200 -#define AR_NO_SPUR 0x8000 -#define AR_BASE_FREQ_2GHZ 2300 -#define AR_BASE_FREQ_5GHZ 4900 -#define AR_SPUR_FEEQ_BOUND_HT40 19 -#define AR_SPUR_FEEQ_BOUND_HT20 10 - int spurmode; - u16 spurchans[AR_EEPROM_MODAL_SPURS][2]; u8 max_txtrig_level; u16 ani_poll_interval; /* ANI poll interval in ms */ + u16 hw_hang_checks; + u16 rimt_first; + u16 rimt_last; /* Platform specific config */ + u32 aspm_l1_fix; u32 xlna_gpio; + u32 ant_ctrl_comm2g_switch_enable; bool xatten_margin_cfg; + bool alt_mingainidx; + u8 pll_pwrsave; + bool tx_gain_buffalo; + bool led_active_high; }; enum ath9k_int { @@ -364,55 +413,31 @@ enum ath9k_int { ATH9K_INT_NOCARD = 0xffffffff }; -#define CHANNEL_CCK 0x00020 -#define CHANNEL_OFDM 0x00040 -#define CHANNEL_2GHZ 0x00080 -#define CHANNEL_5GHZ 0x00100 -#define CHANNEL_PASSIVE 0x00200 -#define CHANNEL_DYN 0x00400 -#define CHANNEL_HALF 0x04000 -#define CHANNEL_QUARTER 0x08000 -#define CHANNEL_HT20 0x10000 -#define CHANNEL_HT40PLUS 0x20000 -#define CHANNEL_HT40MINUS 0x40000 - -#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) -#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) -#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) -#define CHANNEL_G_HT20 (CHANNEL_2GHZ|CHANNEL_HT20) -#define CHANNEL_A_HT20 (CHANNEL_5GHZ|CHANNEL_HT20) -#define CHANNEL_G_HT40PLUS (CHANNEL_2GHZ|CHANNEL_HT40PLUS) -#define CHANNEL_G_HT40MINUS (CHANNEL_2GHZ|CHANNEL_HT40MINUS) -#define CHANNEL_A_HT40PLUS (CHANNEL_5GHZ|CHANNEL_HT40PLUS) -#define CHANNEL_A_HT40MINUS (CHANNEL_5GHZ|CHANNEL_HT40MINUS) -#define CHANNEL_ALL \ - (CHANNEL_OFDM| \ - CHANNEL_CCK| \ - CHANNEL_2GHZ | \ - CHANNEL_5GHZ | \ - CHANNEL_HT20 | \ - CHANNEL_HT40PLUS | \ - CHANNEL_HT40MINUS) - #define MAX_RTT_TABLE_ENTRY 6 #define MAX_IQCAL_MEASUREMENT 8 #define MAX_CL_TAB_ENTRY 16 #define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j)) +enum ath9k_cal_flags { + RTT_DONE, + PAPRD_PACKET_SENT, + PAPRD_DONE, + NFCAL_PENDING, + NFCAL_INTF, + TXIQCAL_DONE, + TXCLCAL_DONE, + SW_PKDET_DONE, + LONGCAL_PENDING, +}; + struct ath9k_hw_cal_data { u16 channel; - u32 channelFlags; - u32 chanmode; + u16 channelFlags; + unsigned long cal_flags; int32_t CalValid; int8_t iCoff; int8_t qCoff; - bool rtt_done; - bool paprd_packet_sent; - bool paprd_done; - bool nfcal_pending; - bool nfcal_interference; - bool done_txiqcal_once; - bool done_txclcal_once; + u8 caldac[2]; u16 small_signal_gain[AR9300_MAX_CHAINS]; u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ]; u32 num_measures[AR9300_MAX_CHAINS]; @@ -425,33 +450,34 @@ struct ath9k_hw_cal_data { struct ath9k_channel { struct ieee80211_channel *chan; u16 channel; - u32 channelFlags; - u32 chanmode; + u16 channelFlags; s16 noisefloor; }; -#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \ - (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \ - (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \ - (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS)) -#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0) -#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) -#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) -#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0) -#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0) +#define CHANNEL_5GHZ BIT(0) +#define CHANNEL_HALF BIT(1) +#define CHANNEL_QUARTER BIT(2) +#define CHANNEL_HT BIT(3) +#define CHANNEL_HT40PLUS BIT(4) +#define CHANNEL_HT40MINUS BIT(5) + +#define IS_CHAN_5GHZ(_c) (!!((_c)->channelFlags & CHANNEL_5GHZ)) +#define IS_CHAN_2GHZ(_c) (!IS_CHAN_5GHZ(_c)) + +#define IS_CHAN_HALF_RATE(_c) (!!((_c)->channelFlags & CHANNEL_HALF)) +#define IS_CHAN_QUARTER_RATE(_c) (!!((_c)->channelFlags & CHANNEL_QUARTER)) #define IS_CHAN_A_FAST_CLOCK(_ah, _c) \ - ((((_c)->channelFlags & CHANNEL_5GHZ) != 0) && \ - ((_ah)->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK)) - -/* These macros check chanmode and not channelFlags */ -#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B) -#define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) || \ - ((_c)->chanmode == CHANNEL_G_HT20)) -#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) || \ - ((_c)->chanmode == CHANNEL_A_HT40MINUS) || \ - ((_c)->chanmode == CHANNEL_G_HT40PLUS) || \ - ((_c)->chanmode == CHANNEL_G_HT40MINUS)) -#define IS_CHAN_HT(_c) (IS_CHAN_HT20((_c)) || IS_CHAN_HT40((_c))) + (IS_CHAN_5GHZ(_c) && ((_ah)->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK)) + +#define IS_CHAN_HT(_c) ((_c)->channelFlags & CHANNEL_HT) + +#define IS_CHAN_HT20(_c) (IS_CHAN_HT(_c) && !IS_CHAN_HT40(_c)) + +#define IS_CHAN_HT40(_c) \ + (!!((_c)->channelFlags & (CHANNEL_HT40PLUS | CHANNEL_HT40MINUS))) + +#define IS_CHAN_HT40PLUS(_c) ((_c)->channelFlags & CHANNEL_HT40PLUS) +#define IS_CHAN_HT40MINUS(_c) ((_c)->channelFlags & CHANNEL_HT40MINUS) enum ath9k_power_mode { ATH9K_PM_AWAKE = 0, @@ -478,10 +504,6 @@ struct ath9k_beacon_state { u32 bs_intval; #define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */ u32 bs_dtimperiod; - u16 bs_cfpperiod; - u16 bs_cfpmaxduration; - u32 bs_cfpnext; - u16 bs_timoffset; u16 bs_bmissthreshold; u32 bs_sleepduration; u32 bs_tsfoor_threshold; @@ -517,12 +539,6 @@ struct ath9k_hw_version { #define AR_GENTMR_BIT(_index) (1 << (_index)) -/* - * Using de Bruijin sequence to look up 1's index in a 32 bit number - * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001 - */ -#define debruijn32 0x077CB531U - struct ath_gen_timer_configuration { u32 next_addr; u32 period_addr; @@ -538,12 +554,9 @@ struct ath_gen_timer { }; struct ath_gen_timer_table { - u32 gen_timer_index[32]; struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER]; - union { - unsigned long timer_bits; - u16 val; - } timer_mask; + u16 timer_mask; + bool tsf2_enabled; }; struct ath_hw_antcomb_conf { @@ -553,6 +566,7 @@ struct ath_hw_antcomb_conf { u8 main_gaintb; u8 alt_gaintb; int lna1_lna2_delta; + int lna1_lna2_switch_delta; u8 div_group; }; @@ -613,6 +627,10 @@ struct ath_hw_radar_conf { * register settings through the register initialization. */ struct ath_hw_private_ops { + void (*init_hang_checks)(struct ath_hw *ah); + bool (*detect_mac_hang)(struct ath_hw *ah); + bool (*detect_bb_hang)(struct ath_hw *ah); + /* Calibration ops */ void (*init_cal_settings)(struct ath_hw *ah); bool (*init_cal)(struct ath_hw *ah, struct ath9k_channel *chan); @@ -652,6 +670,10 @@ struct ath_hw_private_ops { /* ANI */ void (*ani_cache_ini_regs)(struct ath_hw *ah); + +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + bool (*is_aic_enabled)(struct ath_hw *ah); +#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ }; /** @@ -688,7 +710,7 @@ struct ath_spec_scan { /** * struct ath_hw_ops - callbacks used by hardware code and driver code * - * This structure contains callbacks designed to to be used internally by + * This structure contains callbacks designed to be used internally by * hardware code and also by the lower level driver. * * @config_pci_powersave: @@ -703,30 +725,39 @@ struct ath_hw_ops { bool power_off); void (*rx_enable)(struct ath_hw *ah); void (*set_desc_link)(void *ds, u32 link); - bool (*calibrate)(struct ath_hw *ah, - struct ath9k_channel *chan, - u8 rxchainmask, - bool longcal); - bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked); + int (*calibrate)(struct ath_hw *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal); + bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked, + u32 *sync_cause_p); void (*set_txdesc)(struct ath_hw *ah, void *ds, struct ath_tx_info *i); int (*proc_txdesc)(struct ath_hw *ah, void *ds, struct ath_tx_status *ts); + int (*get_duration)(struct ath_hw *ah, const void *ds, int index); void (*antdiv_comb_conf_get)(struct ath_hw *ah, struct ath_hw_antcomb_conf *antconf); void (*antdiv_comb_conf_set)(struct ath_hw *ah, struct ath_hw_antcomb_conf *antconf); - void (*antctrl_shared_chain_lnadiv)(struct ath_hw *hw, bool enable); void (*spectral_scan_config)(struct ath_hw *ah, struct ath_spec_scan *param); void (*spectral_scan_trigger)(struct ath_hw *ah); void (*spectral_scan_wait)(struct ath_hw *ah); + + void (*tx99_start)(struct ath_hw *ah, u32 qnum); + void (*tx99_stop)(struct ath_hw *ah); + void (*tx99_set_txpower)(struct ath_hw *ah, u8 power); + +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + void (*set_bt_ant_diversity)(struct ath_hw *hw, bool enable); +#endif }; struct ath_nf_limits { s16 max; s16 min; s16 nominal; + s16 cal[AR5416_MAX_CHAINS]; + s16 pwr[AR5416_MAX_CHAINS]; }; enum ath_cal_list { @@ -739,6 +770,7 @@ enum ath_cal_list { #define AH_USE_EEPROM 0x1 #define AH_UNPLUGGED 0x2 /* The card has been physically removed. */ #define AH_FASTCC 0x4 +#define AH_NO_EEP_SWAP 0x8 /* Do not swap EEPROM data */ struct ath_hw { struct ath_ops reg_ops; @@ -760,12 +792,12 @@ struct ath_hw { } eeprom; const struct eeprom_ops *eep_ops; - bool sw_mgmt_crypto; + bool sw_mgmt_crypto_tx; + bool sw_mgmt_crypto_rx; bool is_pciexpress; bool aspm_enabled; bool is_monitoring; bool need_an_top2_fixup; - bool shared_chain_lnadiv; u16 tx_trig_level; u32 nf_regs[6]; @@ -775,6 +807,7 @@ struct ath_hw { u32 rfkill_gpio; u32 rfkill_polarity; u32 ah_flags; + s16 nf_override; bool reset_power_on; bool htc_reset_init; @@ -787,6 +820,7 @@ struct ath_hw { struct ath9k_pacal_info pacal_info; struct ar5416Stats stats; struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES]; + DECLARE_BITMAP(pending_del_keymap, ATH_KEYMAX); enum ath9k_int imask; u32 imrs2_reg; @@ -797,11 +831,11 @@ struct ath_hw { u32 txurn_interrupt_mask; atomic_t intr_ref_cnt; bool chip_fullsleep; - u32 atim_window; u32 modes_index; /* Calibration */ u32 supp_cals; + unsigned long cal_start_time; struct ath9k_cal_list iq_caldata; struct ath9k_cal_list adcgain_caldata; struct ath9k_cal_list adcdc_caldata; @@ -876,6 +910,7 @@ struct ath_hw { u32 gpio_mask; u32 gpio_val; + struct ar5416IniArray ini_dfs; struct ar5416IniArray iniModes; struct ar5416IniArray iniCommon; struct ar5416IniArray iniBB_RfGain; @@ -892,7 +927,7 @@ struct ath_hw { struct ar5416IniArray iniCckfirJapan2484; struct ar5416IniArray iniModes_9271_ANI_reg; struct ar5416IniArray ini_radio_post_sys2ant; - struct ar5416IniArray ini_modes_rxgain_5g_xlna; + struct ar5416IniArray ini_modes_rxgain_xlna; struct ar5416IniArray ini_modes_rxgain_bb_core; struct ar5416IniArray ini_modes_rxgain_bb_postamble; @@ -932,14 +967,27 @@ struct ath_hw { /* Enterprise mode cap */ u32 ent_mode; -#ifdef CONFIG_PM_SLEEP - u32 wow_event_mask; +#ifdef CONFIG_ATH9K_WOW + struct ath9k_hw_wow wow; #endif bool is_clk_25mhz; int (*get_mac_revision)(void); int (*external_reset)(void); + bool disable_2ghz; + bool disable_5ghz; const struct firmware *eeprom_blob; + u16 *nvmem_blob; /* devres managed */ + size_t nvmem_blob_len; + + struct ath_dynack dynack; + + bool tpc_enabled; + u8 tx_power[Ar5416RateSize]; + u8 tx_power_stbc[Ar5416RateSize]; + bool msi_enabled; + u32 msi_mask; + u32 msi_reg; }; struct ath_bus_ops { @@ -984,10 +1032,11 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah); u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan); /* GPIO / RFKILL / Antennae */ -void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio); +void ath9k_hw_gpio_request_in(struct ath_hw *ah, u32 gpio, const char *label); +void ath9k_hw_gpio_request_out(struct ath_hw *ah, u32 gpio, const char *label, + u32 ah_signal_type); +void ath9k_hw_gpio_free(struct ath_hw *ah, u32 gpio); u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio); -void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio, - u32 ah_signal_type); void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val); void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna); @@ -997,6 +1046,7 @@ void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan, bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array, int column, unsigned int *writecnt); +void ath9k_hw_read_array(struct ath_hw *ah, u32 array[][2], int size); u32 ath9k_hw_reverse_bits(u32 val, u32 n); u16 ath9k_hw_computetxtime(struct ath_hw *ah, u8 phy, int kbps, @@ -1016,24 +1066,19 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah); u64 ath9k_hw_gettsf64(struct ath_hw *ah); void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); +u32 ath9k_hw_get_tsf_offset(ktime_t last, ktime_t cur); void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set); void ath9k_hw_init_global_settings(struct ath_hw *ah); u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); -void ath9k_hw_set11nmac2040(struct ath_hw *ah); +void ath9k_hw_set11nmac2040(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, const struct ath9k_beacon_state *bs); +void ath9k_hw_check_nav(struct ath_hw *ah); bool ath9k_hw_check_alive(struct ath_hw *ah); bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); -#ifdef CONFIG_ATH9K_DEBUGFS -void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause); -#else -static inline void ath9k_debug_sync_cause(struct ath_common *common, - u32 sync_cause) {} -#endif - /* Generic hw timer primitives */ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, void (*trigger)(void *), @@ -1044,6 +1089,7 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, u32 timer_next, u32 timer_period); +void ath9k_hw_gen_timer_start_tsf2(struct ath_hw *ah); void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer); void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); @@ -1068,6 +1114,7 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah); * Code specific to AR9003, we stuff these here to avoid callbacks * for older families */ +bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah); void ar9003_hw_bb_watchdog_config(struct ath_hw *ah); void ar9003_hw_bb_watchdog_read(struct ath_hw *ah); void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah); @@ -1083,6 +1130,12 @@ int ar9003_paprd_init_table(struct ath_hw *ah); bool ar9003_paprd_is_done(struct ath_hw *ah); bool ar9003_is_paprd_enabled(struct ath_hw *ah); void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx); +void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array, + struct ath9k_channel *chan); +void ar5008_hw_cmn_spur_mitigate(struct ath_hw *ah, + struct ath9k_channel *chan, int bin); +void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array, + struct ath9k_channel *chan, int ht40_delta); /* Hardware family op attach helpers */ int ar5008_hw_attach_phy_ops(struct ath_hw *ah); @@ -1100,7 +1153,12 @@ void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); +void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us); +void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us); +void ath9k_hw_setslottime(struct ath_hw *ah, u32 us); + #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT +void ar9003_hw_attach_aic_ops(struct ath_hw *ah); static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah) { return ah->btcoex_hw.enabled; @@ -1118,6 +1176,9 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) return ah->btcoex_hw.scheme; } #else +static inline void ar9003_hw_attach_aic_ops(struct ath_hw *ah) +{ +} static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah) { return false; @@ -1137,24 +1198,20 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ -#ifdef CONFIG_PM_SLEEP -const char *ath9k_hw_wow_event_to_string(u32 wow_event); -void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, - u8 *user_mask, int pattern_count, - int pattern_len); +#ifdef CONFIG_ATH9K_WOW +int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, + u8 *user_mask, int pattern_count, + int pattern_len); u32 ath9k_hw_wow_wakeup(struct ath_hw *ah); void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable); #else -static inline const char *ath9k_hw_wow_event_to_string(u32 wow_event) -{ - return NULL; -} -static inline void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, - u8 *user_pattern, - u8 *user_mask, - int pattern_count, - int pattern_len) +static inline int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, + u8 *user_pattern, + u8 *user_mask, + int pattern_count, + int pattern_len) { + return 0; } static inline u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 16f8b201642b..ee951493e993 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -18,9 +18,12 @@ #include <linux/dma-mapping.h> #include <linux/slab.h> -#include <linux/ath9k_platform.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_net.h> +#include <linux/nvmem-consumer.h> #include <linux/relay.h> +#include <linux/dmi.h> #include <net/ieee80211_radiotap.h> #include "ath9k.h" @@ -34,7 +37,6 @@ static char *dev_info = "ath9k"; MODULE_AUTHOR("Atheros Communications"); MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); -MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); MODULE_LICENSE("Dual BSD/GPL"); static unsigned int ath9k_debug = ATH_DBG_DEFAULT; @@ -45,116 +47,39 @@ int ath9k_modparam_nohwcrypt; module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); -int led_blink; -module_param_named(blink, led_blink, int, 0444); +int ath9k_led_blink; +module_param_named(blink, ath9k_led_blink, int, 0444); MODULE_PARM_DESC(blink, "Enable LED blink on activity"); +static int ath9k_led_active_high = -1; +module_param_named(led_active_high, ath9k_led_active_high, int, 0444); +MODULE_PARM_DESC(led_active_high, "Invert LED polarity"); + static int ath9k_btcoex_enable; module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444); MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); -static int ath9k_enable_diversity; -module_param_named(enable_diversity, ath9k_enable_diversity, int, 0444); -MODULE_PARM_DESC(enable_diversity, "Enable Antenna diversity for AR9565"); - -bool is_ath9k_unloaded; -/* We use the hw_value as an index into our private channel structure */ +static int ath9k_bt_ant_diversity; +module_param_named(bt_ant_diversity, ath9k_bt_ant_diversity, int, 0444); +MODULE_PARM_DESC(bt_ant_diversity, "Enable WLAN/BT RX antenna diversity"); -#define CHAN2G(_freq, _idx) { \ - .band = IEEE80211_BAND_2GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} +static int ath9k_ps_enable; +module_param_named(ps_enable, ath9k_ps_enable, int, 0444); +MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); -#define CHAN5G(_freq, _idx) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_idx), \ - .max_power = 20, \ -} - -/* Some 2 GHz radios are actually tunable on 2312-2732 - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static const struct ieee80211_channel ath9k_2ghz_chantable[] = { - CHAN2G(2412, 0), /* Channel 1 */ - CHAN2G(2417, 1), /* Channel 2 */ - CHAN2G(2422, 2), /* Channel 3 */ - CHAN2G(2427, 3), /* Channel 4 */ - CHAN2G(2432, 4), /* Channel 5 */ - CHAN2G(2437, 5), /* Channel 6 */ - CHAN2G(2442, 6), /* Channel 7 */ - CHAN2G(2447, 7), /* Channel 8 */ - CHAN2G(2452, 8), /* Channel 9 */ - CHAN2G(2457, 9), /* Channel 10 */ - CHAN2G(2462, 10), /* Channel 11 */ - CHAN2G(2467, 11), /* Channel 12 */ - CHAN2G(2472, 12), /* Channel 13 */ - CHAN2G(2484, 13), /* Channel 14 */ -}; +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT -/* Some 5 GHz radios are actually tunable on XXXX-YYYY - * on 5 MHz steps, we support the channels which we know - * we have calibration data for all cards though to make - * this static */ -static const struct ieee80211_channel ath9k_5ghz_chantable[] = { - /* _We_ call this UNII 1 */ - CHAN5G(5180, 14), /* Channel 36 */ - CHAN5G(5200, 15), /* Channel 40 */ - CHAN5G(5220, 16), /* Channel 44 */ - CHAN5G(5240, 17), /* Channel 48 */ - /* _We_ call this UNII 2 */ - CHAN5G(5260, 18), /* Channel 52 */ - CHAN5G(5280, 19), /* Channel 56 */ - CHAN5G(5300, 20), /* Channel 60 */ - CHAN5G(5320, 21), /* Channel 64 */ - /* _We_ call this "Middle band" */ - CHAN5G(5500, 22), /* Channel 100 */ - CHAN5G(5520, 23), /* Channel 104 */ - CHAN5G(5540, 24), /* Channel 108 */ - CHAN5G(5560, 25), /* Channel 112 */ - CHAN5G(5580, 26), /* Channel 116 */ - CHAN5G(5600, 27), /* Channel 120 */ - CHAN5G(5620, 28), /* Channel 124 */ - CHAN5G(5640, 29), /* Channel 128 */ - CHAN5G(5660, 30), /* Channel 132 */ - CHAN5G(5680, 31), /* Channel 136 */ - CHAN5G(5700, 32), /* Channel 140 */ - /* _We_ call this UNII 3 */ - CHAN5G(5745, 33), /* Channel 149 */ - CHAN5G(5765, 34), /* Channel 153 */ - CHAN5G(5785, 35), /* Channel 157 */ - CHAN5G(5805, 36), /* Channel 161 */ - CHAN5G(5825, 37), /* Channel 165 */ -}; +int ath9k_use_chanctx; +module_param_named(use_chanctx, ath9k_use_chanctx, int, 0444); +MODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency"); -/* Atheros hardware rate code addition for short premble */ -#define SHPCHECK(__hw_rate, __flags) \ - ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) +#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ -#define RATE(_bitrate, _hw_rate, _flags) { \ - .bitrate = (_bitrate), \ - .flags = (_flags), \ - .hw_value = (_hw_rate), \ - .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ -} +int ath9k_use_msi; +module_param_named(use_msi, ath9k_use_msi, int, 0444); +MODULE_PARM_DESC(use_msi, "Use MSI instead of INTx if possible"); -static struct ieee80211_rate ath9k_legacy_rates[] = { - RATE(10, 0x1b, 0), - RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), - RATE(60, 0x0b, 0), - RATE(90, 0x0f, 0), - RATE(120, 0x0a, 0), - RATE(180, 0x0e, 0), - RATE(240, 0x09, 0), - RATE(360, 0x0d, 0), - RATE(480, 0x08, 0), - RATE(540, 0x0c, 0), -}; +bool is_ath9k_unloaded; #ifdef CONFIG_MAC80211_LEDS static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = { @@ -171,8 +96,73 @@ static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = { }; #endif +static int __init set_use_msi(const struct dmi_system_id *dmi) +{ + ath9k_use_msi = 1; + return 1; +} + +static const struct dmi_system_id ath9k_quirks[] __initconst = { + { + .callback = set_use_msi, + .ident = "Dell Inspiron 24-3460", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 24-3460"), + }, + }, + { + .callback = set_use_msi, + .ident = "Dell Vostro 3262", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3262"), + }, + }, + { + .callback = set_use_msi, + .ident = "Dell Inspiron 3472", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 3472"), + }, + }, + { + .callback = set_use_msi, + .ident = "Dell Vostro 15-3572", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 15-3572"), + }, + }, + { + .callback = set_use_msi, + .ident = "Dell Inspiron 14-3473", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 14-3473"), + }, + }, + {} +}; + static void ath9k_deinit_softc(struct ath_softc *sc); +static void ath9k_op_ps_wakeup(struct ath_common *common) +{ + ath9k_ps_wakeup(common->priv); +} + +static void ath9k_op_ps_restore(struct ath_common *common) +{ + ath9k_ps_restore(common->priv); +} + +static const struct ath_ps_ops ath9k_ps_ops = { + .wakeup = ath9k_op_ps_wakeup, + .restore = ath9k_op_ps_restore, +}; + /* * Read and write, they both share the same lock. We do this to serialize * reads and writes on Atheros 802.11n PCI devices only. This is required @@ -181,9 +171,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc); static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) { - struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { unsigned long flags; @@ -196,9 +186,9 @@ static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) { - struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; u32 val; if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { @@ -211,6 +201,16 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) return val; } +static void ath9k_multi_ioread32(void *hw_priv, u32 *addr, + u32 *val, u16 count) +{ + int i; + + for (i = 0; i < count; i++) + val[i] = ath9k_ioread32(hw_priv, addr[i]); +} + + static unsigned int __ath9k_reg_rmw(struct ath_softc *sc, u32 reg_offset, u32 set, u32 clr) { @@ -226,10 +226,10 @@ static unsigned int __ath9k_reg_rmw(struct ath_softc *sc, u32 reg_offset, static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) { - struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; - unsigned long uninitialized_var(flags); + struct ath_softc *sc = common->priv; + unsigned long flags; u32 val; if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { @@ -246,64 +246,6 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl /* Initialization */ /**************************/ -static void setup_ht_cap(struct ath_softc *sc, - struct ieee80211_sta_ht_cap *ht_info) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u8 tx_streams, rx_streams; - int i, max_streams; - - ht_info->ht_supported = true; - ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_SM_PS | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_DSSSCCK40; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC) - ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) - ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - - ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; - - if (AR_SREV_9330(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah)) - max_streams = 1; - else if (AR_SREV_9462(ah)) - max_streams = 2; - else if (AR_SREV_9300_20_OR_LATER(ah)) - max_streams = 3; - else - max_streams = 2; - - if (AR_SREV_9280_20_OR_LATER(ah)) { - if (max_streams >= 2) - ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; - ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - } - - /* set up supported mcs set */ - memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams); - rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams); - - ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n", - tx_streams, rx_streams); - - if (tx_streams != rx_streams) { - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; - ht_info->mcs.tx_params |= ((tx_streams - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); - } - - for (i = 0; i < rx_streams; i++) - ht_info->mcs.rx_mask[i] = 0xff; - - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; -} - static void ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { @@ -314,18 +256,22 @@ static void ath9k_reg_notifier(struct wiphy *wiphy, ath_reg_notifier_apply(wiphy, request, reg); + /* synchronize DFS detector if regulatory domain changed */ + if (sc->dfs_detector != NULL) + sc->dfs_detector->set_dfs_domain(sc->dfs_detector, + request->dfs_region); + /* Set tx power */ - if (ah->curchan) { - sc->config.txpowlimit = 2 * ah->curchan->chan->max_power; - ath9k_ps_wakeup(sc); - ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); - sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit; - /* synchronize DFS detector if regulatory domain changed */ - if (sc->dfs_detector != NULL) - sc->dfs_detector->set_dfs_domain(sc->dfs_detector, - request->dfs_region); - ath9k_ps_restore(sc); - } + if (!ah->curchan) + return; + + sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power; + ath9k_ps_wakeup(sc); + ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); + ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, + sc->cur_chan->txpower, + &sc->cur_chan->cur_txpower); + ath9k_ps_restore(sc); } /* @@ -339,7 +285,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, { struct ath_common *common = ath9k_hw_common(sc->sc_ah); u8 *ds; - struct ath_buf *bf; int i, bsize, desc_len; ath_dbg(common, CONFIG, "%s DMA: %u buffers %u desc/buf\n", @@ -385,39 +330,74 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, if (!dd->dd_desc) return -ENOMEM; - ds = (u8 *) dd->dd_desc; + ds = dd->dd_desc; ath_dbg(common, CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", name, ds, (u32) dd->dd_desc_len, ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); /* allocate buffers */ - bsize = sizeof(struct ath_buf) * nbuf; - bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL); - if (!bf) - return -ENOMEM; + if (is_tx) { + struct ath_buf *bf; + + bsize = sizeof(struct ath_buf) * nbuf; + bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL); + if (!bf) + return -ENOMEM; + + for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); + + if (!(sc->sc_ah->caps.hw_caps & + ATH9K_HW_CAP_4KB_SPLITTRANS)) { + /* + * Skip descriptor addresses which can cause 4KB + * boundary crossing (addr + length) with a 32 dword + * descriptor fetch. + */ + while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { + BUG_ON((caddr_t) bf->bf_desc >= + ((caddr_t) dd->dd_desc + + dd->dd_desc_len)); + + ds += (desc_len * ndesc); + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); + } + } + list_add_tail(&bf->list, head); + } + } else { + struct ath_rxbuf *bf; + + bsize = sizeof(struct ath_rxbuf) * nbuf; + bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL); + if (!bf) + return -ENOMEM; - for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { - bf->bf_desc = ds; - bf->bf_daddr = DS2PHYS(dd, ds); - - if (!(sc->sc_ah->caps.hw_caps & - ATH9K_HW_CAP_4KB_SPLITTRANS)) { - /* - * Skip descriptor addresses which can cause 4KB - * boundary crossing (addr + length) with a 32 dword - * descriptor fetch. - */ - while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { - BUG_ON((caddr_t) bf->bf_desc >= - ((caddr_t) dd->dd_desc + - dd->dd_desc_len)); - - ds += (desc_len * ndesc); - bf->bf_desc = ds; - bf->bf_daddr = DS2PHYS(dd, ds); + for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); + + if (!(sc->sc_ah->caps.hw_caps & + ATH9K_HW_CAP_4KB_SPLITTRANS)) { + /* + * Skip descriptor addresses which can cause 4KB + * boundary crossing (addr + length) with a 32 dword + * descriptor fetch. + */ + while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { + BUG_ON((caddr_t) bf->bf_desc >= + ((caddr_t) dd->dd_desc + + dd->dd_desc_len)); + + ds += (desc_len * ndesc); + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); + } } + list_add_tail(&bf->list, head); } - list_add_tail(&bf->list, head); } return 0; } @@ -428,8 +408,6 @@ static int ath9k_init_queues(struct ath_softc *sc) sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah); sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); - - sc->config.cabqReadytime = ATH_CABQ_READY_TIME; ath_cabq_update(sc); sc->tx.uapsdq = ath_txq_setup(sc, ATH9K_TX_QUEUE_UAPSD, 0); @@ -437,52 +415,6 @@ static int ath9k_init_queues(struct ath_softc *sc) for (i = 0; i < IEEE80211_NUM_ACS; i++) { sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i); sc->tx.txq_map[i]->mac80211_qnum = i; - sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH; - } - return 0; -} - -static int ath9k_init_channels_rates(struct ath_softc *sc) -{ - void *channels; - - BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) + - ARRAY_SIZE(ath9k_5ghz_chantable) != - ATH9K_NUM_CHANNELS); - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { - channels = devm_kzalloc(sc->dev, - sizeof(ath9k_2ghz_chantable), GFP_KERNEL); - if (!channels) - return -ENOMEM; - - memcpy(channels, ath9k_2ghz_chantable, - sizeof(ath9k_2ghz_chantable)); - sc->sbands[IEEE80211_BAND_2GHZ].channels = channels; - sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - sc->sbands[IEEE80211_BAND_2GHZ].n_channels = - ARRAY_SIZE(ath9k_2ghz_chantable); - sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; - sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates); - } - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) { - channels = devm_kzalloc(sc->dev, - sizeof(ath9k_5ghz_chantable), GFP_KERNEL); - if (!channels) - return -ENOMEM; - - memcpy(channels, ath9k_5ghz_chantable, - sizeof(ath9k_5ghz_chantable)); - sc->sbands[IEEE80211_BAND_5GHZ].channels = channels; - sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; - sc->sbands[IEEE80211_BAND_5GHZ].n_channels = - ARRAY_SIZE(ath9k_5ghz_chantable); - sc->sbands[IEEE80211_BAND_5GHZ].bitrates = - ath9k_legacy_rates + 4; - sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = - ARRAY_SIZE(ath9k_legacy_rates) - 4; } return 0; } @@ -492,12 +424,11 @@ static void ath9k_init_misc(struct ath_softc *sc) struct ath_common *common = ath9k_hw_common(sc->sc_ah); int i = 0; - setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); + timer_setup(&common->ani.timer, ath_ani_calibrate, 0); - sc->last_rssi = ATH_RSSI_DUMMY_MARKER; - sc->config.txpowlimit = ATH_TXPOWER_MAX; - memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); - sc->beacon.slottime = ATH9K_SLOT_TIME_9; + common->last_rssi = ATH_RSSI_DUMMY_MARKER; + eth_broadcast_addr(common->bssidmask); + sc->beacon.slottime = 9; for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) sc->beacon.bslot[i] = NULL; @@ -505,19 +436,24 @@ static void ath9k_init_misc(struct ath_softc *sc) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; - sc->spec_config.enabled = 0; - sc->spec_config.short_repeat = true; - sc->spec_config.count = 8; - sc->spec_config.endless = false; - sc->spec_config.period = 0xFF; - sc->spec_config.fft_period = 0xF; + sc->spec_priv.ah = sc->sc_ah; + sc->spec_priv.spec_config.enabled = 0; + sc->spec_priv.spec_config.short_repeat = true; + sc->spec_priv.spec_config.count = 8; + sc->spec_priv.spec_config.endless = false; + sc->spec_priv.spec_config.period = 0xFF; + sc->spec_priv.spec_config.fft_period = 0xF; } -static void ath9k_init_platform(struct ath_softc *sc) +static void ath9k_init_pcoem_platform(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; + struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); + if (!IS_ENABLED(CONFIG_ATH9K_PCOEM)) + return; + if (common->bus_ops->ath_bus_type != ATH_PCI) return; @@ -525,13 +461,66 @@ static void ath9k_init_platform(struct ath_softc *sc) ATH9K_PCI_CUS230)) { ah->config.xlna_gpio = 9; ah->config.xatten_margin_cfg = true; + ah->config.alt_mingainidx = true; + ah->config.ant_ctrl_comm2g_switch_enable = 0x000BBB88; + sc->ant_comb.low_rssi_thresh = 20; + sc->ant_comb.fast_div_bias = 3; ath_info(common, "Set parameters for %s\n", (sc->driver_data & ATH9K_PCI_CUS198) ? "CUS198" : "CUS230"); - } else if (sc->driver_data & ATH9K_PCI_CUS217) { + } + + if (sc->driver_data & ATH9K_PCI_CUS217) ath_info(common, "CUS217 card detected\n"); + + if (sc->driver_data & ATH9K_PCI_CUS252) + ath_info(common, "CUS252 card detected\n"); + + if (sc->driver_data & ATH9K_PCI_AR9565_1ANT) + ath_info(common, "WB335 1-ANT card detected\n"); + + if (sc->driver_data & ATH9K_PCI_AR9565_2ANT) + ath_info(common, "WB335 2-ANT card detected\n"); + + if (sc->driver_data & ATH9K_PCI_KILLER) + ath_info(common, "Killer Wireless card detected\n"); + + /* + * Some WB335 cards do not support antenna diversity. Since + * we use a hardcoded value for AR9565 instead of using the + * EEPROM/OTP data, remove the combining feature from + * the HW capabilities bitmap. + */ + if (sc->driver_data & (ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_AR9565_2ANT)) { + if (!(sc->driver_data & ATH9K_PCI_BT_ANT_DIV)) + pCap->hw_caps &= ~ATH9K_HW_CAP_ANT_DIV_COMB; + } + + if (sc->driver_data & ATH9K_PCI_BT_ANT_DIV) { + pCap->hw_caps |= ATH9K_HW_CAP_BT_ANT_DIV; + ath_info(common, "Set BT/WLAN RX diversity capability\n"); + } + + if (sc->driver_data & ATH9K_PCI_D3_L1_WAR) { + ah->config.pcie_waen = 0x0040473b; + ath_info(common, "Enable WAR for ASPM D3/L1\n"); } + + /* + * The default value of pll_pwrsave is 1. + * For certain AR9485 cards, it is set to 0. + * For AR9462, AR9565 it's set to 7. + */ + ah->config.pll_pwrsave = 1; + + if (sc->driver_data & ATH9K_PCI_NO_PLL_PWRSAVE) { + ah->config.pll_pwrsave = 0; + ath_info(common, "Disable PLL PowerSave\n"); + } + + if (sc->driver_data & ATH9K_PCI_LED_ACT_HI) + ah->config.led_active_high = true; } static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, @@ -548,7 +537,7 @@ static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, static int ath9k_eeprom_request(struct ath_softc *sc, const char *name) { struct ath9k_eeprom_ctx ec; - struct ath_hw *ah = ah = sc->sc_ah; + struct ath_hw *ah = sc->sc_ah; int err; /* try to load the EEPROM content asynchronously */ @@ -579,11 +568,97 @@ static void ath9k_eeprom_release(struct ath_softc *sc) release_firmware(sc->sc_ah->eeprom_blob); } +static int ath9k_nvmem_request_eeprom(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct nvmem_cell *cell; + void *buf; + size_t len; + int err; + + cell = devm_nvmem_cell_get(sc->dev, "calibration"); + if (IS_ERR(cell)) { + err = PTR_ERR(cell); + + /* nvmem cell might not be defined, or the nvmem + * subsystem isn't included. In this case, follow + * the established "just return 0;" convention + * to say: + * "All good. Nothing to see here. Please go on." + */ + if (err == -ENOENT || err == -EOPNOTSUPP) + return 0; + + return err; + } + + buf = nvmem_cell_read(cell, &len); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + /* run basic sanity checks on the returned nvram cell length. + * That length has to be a multiple of a "u16" (i.e.: & 1). + * Furthermore, it has to be more than "let's say" 512 bytes + * but less than the maximum of AR9300_EEPROM_SIZE (16kb). + */ + if ((len & 1) == 1 || len < 512 || len >= AR9300_EEPROM_SIZE) { + kfree(buf); + return -EINVAL; + } + + /* devres manages the calibration values release on shutdown */ + ah->nvmem_blob = devm_kmemdup(sc->dev, buf, len, GFP_KERNEL); + kfree(buf); + if (!ah->nvmem_blob) + return -ENOMEM; + + ah->nvmem_blob_len = len; + ah->ah_flags &= ~AH_USE_EEPROM; + ah->ah_flags |= AH_NO_EEP_SWAP; + + return 0; +} + +static int ath9k_of_init(struct ath_softc *sc) +{ + struct device_node *np = sc->dev->of_node; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + enum ath_bus_type bus_type = common->bus_ops->ath_bus_type; + char eeprom_name[100]; + int ret; + + if (!of_device_is_available(np)) + return 0; + + ath_dbg(common, CONFIG, "parsing configuration from OF node\n"); + + if (of_property_read_bool(np, "qca,no-eeprom")) { + /* ath9k-eeprom-<bus>-<id>.bin */ + scnprintf(eeprom_name, sizeof(eeprom_name), + "ath9k-eeprom-%s-%s.bin", + ath_bus_type_to_string(bus_type), dev_name(ah->dev)); + + ret = ath9k_eeprom_request(sc, eeprom_name); + if (ret) + return ret; + + ah->ah_flags &= ~AH_USE_EEPROM; + ah->ah_flags |= AH_NO_EEP_SWAP; + } + + ret = of_get_mac_address(np, common->macaddr); + if (ret == -EPROBE_DEFER) + return ret; + + return 0; +} + static int ath9k_init_softc(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops) { - struct ath9k_platform_data *pdata = sc->dev->platform_data; struct ath_hw *ah = NULL; + struct ath9k_hw_capabilities *pCap; struct ath_common *common; int ret = 0, i; int csz = 0; @@ -595,29 +670,30 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ah->dev = sc->dev; ah->hw = sc->hw; ah->hw_version.devid = devid; + ah->ah_flags |= AH_USE_EEPROM; + ah->led_pin = -1; ah->reg_ops.read = ath9k_ioread32; + ah->reg_ops.multi_read = ath9k_multi_ioread32; ah->reg_ops.write = ath9k_iowrite32; ah->reg_ops.rmw = ath9k_reg_rmw; - atomic_set(&ah->intr_ref_cnt, -1); - sc->sc_ah = ah; + pCap = &ah->caps; - sc->dfs_detector = dfs_pattern_detector_init(ah, NL80211_DFS_UNSET); + common = ath9k_hw_common(ah); - if (!pdata) { - ah->ah_flags |= AH_USE_EEPROM; - sc->sc_ah->led_pin = -1; - } else { - sc->sc_ah->gpio_mask = pdata->gpio_mask; - sc->sc_ah->gpio_val = pdata->gpio_val; - sc->sc_ah->led_pin = pdata->led_pin; - ah->is_clk_25mhz = pdata->is_clk_25mhz; - ah->get_mac_revision = pdata->get_mac_revision; - ah->external_reset = pdata->external_reset; - } + /* Will be cleared in ath9k_start() */ + set_bit(ATH_OP_INVALID, &common->op_flags); + + sc->sc_ah = ah; + sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET); + sc->tx99_power = MAX_RATE_POWER + 1; + init_waitqueue_head(&sc->tx_wait); + sc->cur_chan = &sc->chanctx[0]; + if (!ath9k_is_chanctx_enabled()) + sc->cur_chan->hw_queue_base = 0; - common = ath9k_hw_common(ah); common->ops = &ah->reg_ops; common->bus_ops = bus_ops; + common->ps_ops = &ath9k_ps_ops; common->ah = ah; common->hw = sc->hw; common->priv = sc; @@ -628,29 +704,46 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, /* * Platform quirks. */ - ath9k_init_platform(sc); + ath9k_init_pcoem_platform(sc); + + ret = ath9k_of_init(sc); + if (ret) + return ret; + + ret = ath9k_nvmem_request_eeprom(sc); + if (ret) + return ret; + + if (ath9k_led_active_high != -1) + ah->config.led_active_high = ath9k_led_active_high == 1; /* - * Enable Antenna diversity only when BTCOEX is disabled - * and the user manually requests the feature. + * Enable WLAN/BT RX Antenna diversity only when: + * + * - BTCOEX is disabled. + * - the user manually requests the feature. + * - the HW cap is set using the platform data. */ - if (!common->btcoex_enabled && ath9k_enable_diversity) - common->antenna_diversity = 1; + if (!common->btcoex_enabled && ath9k_bt_ant_diversity && + (pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV)) + common->bt_ant_diversity = 1; spin_lock_init(&common->cc_lock); - + spin_lock_init(&sc->intr_lock); spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->sc_pm_lock); + spin_lock_init(&sc->chan_lock); mutex_init(&sc->mutex); - tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); - tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, - (unsigned long)sc); + tasklet_setup(&sc->intr_tq, ath9k_tasklet); + tasklet_setup(&sc->bcon_tasklet, ath9k_beacon_tasklet); + timer_setup(&sc->sleep_timer, ath_ps_full_sleep, 0); INIT_WORK(&sc->hw_reset_work, ath_reset_work); - INIT_WORK(&sc->hw_check_work, ath_hw_check); INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); - setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc); + INIT_DELAYED_WORK(&sc->hw_check_work, ath_hw_check_work); + + ath9k_init_channel_context(sc); /* * Cache line size is used to size and align various @@ -659,20 +752,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ath_read_cachesize(common, &csz); common->cachelsz = csz << 2; /* convert to bytes */ - if (pdata && pdata->eeprom_name) { - ret = ath9k_eeprom_request(sc, pdata->eeprom_name); - if (ret) - return ret; - } - /* Initializes the hardware for all supported chipsets */ ret = ath9k_hw_init(ah); if (ret) goto err_hw; - if (pdata && pdata->macaddr) - memcpy(common->macaddr, pdata->macaddr, ETH_ALEN); - ret = ath9k_init_queues(sc); if (ret) goto err_queues; @@ -681,13 +765,18 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, if (ret) goto err_btcoex; - ret = ath9k_init_channels_rates(sc); + ret = ath9k_cmn_init_channels_rates(common); + if (ret) + goto err_btcoex; + + ret = ath9k_init_p2p(sc); if (ret) goto err_btcoex; ath9k_cmn_init_crypto(sc->sc_ah); ath9k_init_misc(sc); - ath_fill_led_pin(sc); + ath_chanctx_init(sc); + ath9k_offchannel_init(sc); if (common->bus_ops->aspm_init) common->bus_ops->aspm_init(common); @@ -702,6 +791,7 @@ err_queues: ath9k_hw_deinit(ah); err_hw: ath9k_eeprom_release(sc); + dev_kfree_skb_any(sc->tx99_skb); return ret; } @@ -710,14 +800,17 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band) struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct cfg80211_chan_def chandef; int i; - sband = &sc->sbands[band]; + sband = &common->sbands[band]; for (i = 0; i < sband->n_channels; i++) { chan = &sband->channels[i]; ah->curchan = &ah->channels[chan->hw_value]; - ath9k_cmn_update_ichannel(ah->curchan, chan, NL80211_CHAN_HT20); - ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, true); + cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); + ath9k_cmn_get_channel(sc->hw, ah, &chandef); + ath9k_hw_set_txpowerlimit(ah, MAX_COMBINED_POWER, true); } } @@ -727,41 +820,47 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc) struct ath9k_channel *curchan = ah->curchan; if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ); + ath9k_init_band_txpower(sc, NL80211_BAND_2GHZ); if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - ath9k_init_band_txpower(sc, IEEE80211_BAND_5GHZ); + ath9k_init_band_txpower(sc, NL80211_BAND_5GHZ); ah->curchan = curchan; } -void ath9k_reload_chainmask_settings(struct ath_softc *sc) -{ - if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)) - return; - - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); -} - static const struct ieee80211_iface_limit if_limits[] = { - { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_WDS) }, + { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) }, { .max = 8, .types = #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif - BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_AP) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) }, }; +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + +static const struct ieee80211_iface_limit if_limits_multi[] = { + { .max = 2, .types = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, +}; -static const struct ieee80211_iface_limit if_dfs_limits[] = { - { .max = 1, .types = BIT(NL80211_IFTYPE_AP) }, +static const struct ieee80211_iface_combination if_comb_multi[] = { + { + .limits = if_limits_multi, + .n_limits = ARRAY_SIZE(if_limits_multi), + .max_interfaces = 3, + .num_different_channels = 2, + .beacon_int_infra_match = true, + }, }; +#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ + static const struct ieee80211_iface_combination if_comb[] = { { .limits = if_limits, @@ -769,43 +868,60 @@ static const struct ieee80211_iface_combination if_comb[] = { .max_interfaces = 2048, .num_different_channels = 1, .beacon_int_infra_match = true, +#ifdef CONFIG_ATH9K_DFS_CERTIFIED + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40), +#endif }, - { - .limits = if_dfs_limits, - .n_limits = ARRAY_SIZE(if_dfs_limits), - .max_interfaces = 1, - .num_different_channels = 1, - .beacon_int_infra_match = true, - .radar_detect_widths = BIT(NL80211_CHAN_NO_HT) | - BIT(NL80211_CHAN_HT20), - } }; -#ifdef CONFIG_PM -static const struct wiphy_wowlan_support ath9k_wowlan_support = { - .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, - .n_patterns = MAX_NUM_USER_PATTERN, - .pattern_min_len = 1, - .pattern_max_len = MAX_PATTERN_SIZE, -}; -#endif +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT +static void ath9k_set_mcc_capab(struct ath_softc *sc, struct ieee80211_hw *hw) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + + if (!ath9k_is_chanctx_enabled()) + return; -void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) + ieee80211_hw_set(hw, QUEUE_CONTROL); + hw->queues = ATH9K_NUM_TX_QUEUES; + hw->offchannel_tx_hw_queue = hw->queues - 1; + hw->wiphy->iface_combinations = if_comb_multi; + hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi); + hw->wiphy->max_scan_ssids = 255; + hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + hw->wiphy->max_remain_on_channel_duration = 10000; + hw->chanctx_data_size = sizeof(void *); + hw->extra_beacon_tailroom = + sizeof(struct ieee80211_p2p_noa_attr) + 9; + + ath_dbg(common, CHAN_CTX, "Use channel contexts\n"); +} +#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ + +static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_SUPPORTS_PS | - IEEE80211_HW_PS_NULLFUNC_STACK | - IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_REPORTS_TX_ACK_STATUS | - IEEE80211_HW_SUPPORTS_RC_TABLE; + ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); + ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); + ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); + ieee80211_hw_set(hw, SPECTRUM_MGMT); + ieee80211_hw_set(hw, PS_NULLFUNC_STACK); + ieee80211_hw_set(hw, SIGNAL_DBM); + ieee80211_hw_set(hw, RX_INCLUDES_FCS); + ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); + ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); + ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); + + if (ath9k_ps_enable) + ieee80211_hw_set(hw, SUPPORTS_PS); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; + ieee80211_hw_set(hw, AMPDU_AGGREGATION); if (AR_SREV_9280_20_OR_LATER(ah)) hw->radiotap_mcs_details |= @@ -813,45 +929,47 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) } if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) - hw->flags |= IEEE80211_HW_MFP_CAPABLE; - - hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; - - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_WDS) | - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_MESH_POINT); - - hw->wiphy->iface_combinations = if_comb; - hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); + ieee80211_hw_set(hw, MFP_CAPABLE); + + hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | + NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | + NL80211_FEATURE_P2P_GO_CTWIN; + + if (!IS_ENABLED(CONFIG_ATH9K_TX99)) { + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_OCB); + + if (ath9k_is_chanctx_enabled()) + hw->wiphy->interface_modes |= + BIT(NL80211_IFTYPE_P2P_DEVICE); + + hw->wiphy->iface_combinations = if_comb; + hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); + } hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; - -#ifdef CONFIG_PM_SLEEP - if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && - (sc->driver_data & ATH9K_PCI_WOW) && - device_can_wakeup(sc->dev)) - hw->wiphy->wowlan = &ath9k_wowlan_support; - - atomic_set(&sc->wow_sleep_proc_intr, -1); - atomic_set(&sc->wow_got_bmiss_intr, -1); -#endif + hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; + hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; hw->queues = 4; hw->max_rates = 4; - hw->channel_change_time = 5000; - hw->max_listen_interval = 1; + hw->max_listen_interval = 10; hw->max_rate_tries = 10; hw->sta_data_size = sizeof(struct ath_node); hw->vif_data_size = sizeof(struct ath_vif); + hw->txq_data_size = sizeof(struct ath_atx_tid); + hw->extra_tx_headroom = 4; hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1; hw->wiphy->available_antennas_tx = BIT(ah->caps.max_txchains) - 1; @@ -864,15 +982,25 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) sc->ant_tx = hw->wiphy->available_antennas_tx; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &sc->sbands[IEEE80211_BAND_2GHZ]; + hw->wiphy->bands[NL80211_BAND_2GHZ] = + &common->sbands[NL80211_BAND_2GHZ]; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &sc->sbands[IEEE80211_BAND_5GHZ]; + hw->wiphy->bands[NL80211_BAND_5GHZ] = + &common->sbands[NL80211_BAND_5GHZ]; - ath9k_reload_chainmask_settings(sc); +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + ath9k_set_mcc_capab(sc, hw); +#endif + ath9k_init_wow(hw); + ath9k_cmn_reload_chainmask(ah); SET_IEEE80211_PERM_ADDR(hw, common->macaddr); + + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); + wiphy_ext_feature_set(hw->wiphy, + NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); } int ath9k_init_device(u16 devid, struct ath_softc *sc, @@ -920,6 +1048,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, ARRAY_SIZE(ath9k_tpt_blink)); #endif + wiphy_read_of_freq_limits(hw->wiphy); + /* Register with mac80211 */ error = ieee80211_register_hw(hw); if (error) @@ -962,12 +1092,14 @@ static void ath9k_deinit_softc(struct ath_softc *sc) { int i = 0; + ath9k_deinit_p2p(sc); ath9k_deinit_btcoex(sc); for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); + timer_delete_sync(&sc->sleep_timer); ath9k_hw_deinit(sc->sc_ah); if (sc->dfs_detector != NULL) sc->dfs_detector->exit(sc->dfs_detector); @@ -987,6 +1119,7 @@ void ath9k_deinit_device(struct ath_softc *sc) ath9k_ps_restore(sc); ath9k_deinit_debug(sc); + ath9k_deinit_wow(hw); ieee80211_unregister_hw(hw); ath_rx_cleanup(sc); ath9k_deinit_softc(sc); @@ -1000,19 +1133,11 @@ static int __init ath9k_init(void) { int error; - /* Register rate control algorithm */ - error = ath_rate_control_register(); - if (error != 0) { - pr_err("Unable to register rate control algorithm: %d\n", - error); - goto err_out; - } - error = ath_pci_init(); if (error < 0) { pr_err("No PCI devices found, driver not installed\n"); error = -ENODEV; - goto err_rate_unregister; + goto err_out; } error = ath_ahb_init(); @@ -1021,13 +1146,12 @@ static int __init ath9k_init(void) goto err_pci_exit; } + dmi_check_system(ath9k_quirks); + return 0; err_pci_exit: ath_pci_exit(); - - err_rate_unregister: - ath_rate_control_unregister(); err_out: return error; } @@ -1038,7 +1162,6 @@ static void __exit ath9k_exit(void) is_ath9k_unloaded = true; ath_ahb_exit(); ath_pci_exit(); - ath_rate_control_unregister(); pr_info("%s: Driver unloaded\n", dev_info); } module_exit(ath9k_exit); diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index fff5d3ccc663..5d7e3ddb6dbc 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -20,13 +20,13 @@ * TX polling - checks if the TX engine is stuck somewhere * and issues a chip reset if so. */ -void ath_tx_complete_poll_work(struct work_struct *work) +static bool ath_tx_complete_check(struct ath_softc *sc) { - struct ath_softc *sc = container_of(work, struct ath_softc, - tx_complete_work.work); struct ath_txq *txq; int i; - bool needreset = false; + + if (sc->tx99_state) + return true; for (i = 0; i < IEEE80211_NUM_ACS; i++) { txq = sc->tx.txq_map[i]; @@ -34,74 +34,90 @@ void ath_tx_complete_poll_work(struct work_struct *work) ath_txq_lock(sc, txq); if (txq->axq_depth) { if (txq->axq_tx_inprogress) { - needreset = true; ath_txq_unlock(sc, txq); - break; - } else { - txq->axq_tx_inprogress = true; + goto reset; } + + txq->axq_tx_inprogress = true; } - ath_txq_unlock_complete(sc, txq); + ath_txq_unlock(sc, txq); } - if (needreset) { - ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, - "tx hung, resetting the chip\n"); - ath9k_queue_reset(sc, RESET_TYPE_TX_HANG); + return true; + +reset: + ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, + "tx hung, resetting the chip\n"); + ath9k_queue_reset(sc, RESET_TYPE_TX_HANG); + return false; +} + +#define RX_INACTIVE_CHECK_INTERVAL (4 * MSEC_PER_SEC) + +static bool ath_hw_rx_inactive_check(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + u32 interval, count; + + interval = jiffies_to_msecs(jiffies - sc->rx_active_check_time); + count = sc->rx_active_count; + + if (interval < RX_INACTIVE_CHECK_INTERVAL) + return true; /* too soon to check */ + + sc->rx_active_count = 0; + sc->rx_active_check_time = jiffies; + + /* Need at least one interrupt per second, and we should only react if + * we are within a factor two of the expected interval + */ + if (interval > RX_INACTIVE_CHECK_INTERVAL * 2 || + count >= interval / MSEC_PER_SEC) + return true; + + ath_dbg(common, RESET, + "RX inactivity detected. Schedule chip reset\n"); + ath9k_queue_reset(sc, RESET_TYPE_RX_INACTIVE); + + return false; +} + +void ath_hw_check_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + hw_check_work.work); + + if (!ath_hw_check(sc) || !ath_tx_complete_check(sc) || + !ath_hw_rx_inactive_check(sc)) return; - } - ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, - msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT)); + ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work, + msecs_to_jiffies(ATH_HW_CHECK_POLL_INT)); } /* * Checks if the BB/MAC is hung. */ -void ath_hw_check(struct work_struct *work) +bool ath_hw_check(struct ath_softc *sc) { - struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); struct ath_common *common = ath9k_hw_common(sc->sc_ah); - unsigned long flags; - int busy; - u8 is_alive, nbeacon = 1; enum ath_reset_type type; + bool is_alive; ath9k_ps_wakeup(sc); + is_alive = ath9k_hw_check_alive(sc->sc_ah); - if (is_alive && !AR_SREV_9300(sc->sc_ah)) - goto out; - else if (!is_alive && AR_SREV_9300(sc->sc_ah)) { + if (!is_alive) { ath_dbg(common, RESET, - "DCU stuck is detected. Schedule chip reset\n"); + "HW hang detected, schedule chip reset\n"); type = RESET_TYPE_MAC_HANG; - goto sched_reset; + ath9k_queue_reset(sc, type); } - spin_lock_irqsave(&common->cc_lock, flags); - busy = ath_update_survey_stats(sc); - spin_unlock_irqrestore(&common->cc_lock, flags); - - ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n", - busy, sc->hw_busy_count + 1); - if (busy >= 99) { - if (++sc->hw_busy_count >= 3) { - type = RESET_TYPE_BB_HANG; - goto sched_reset; - } - } else if (busy >= 0) { - sc->hw_busy_count = 0; - nbeacon = 3; - } - - ath_start_rx_poll(sc, nbeacon); - goto out; - -sched_reset: - ath9k_queue_reset(sc, type); -out: ath9k_ps_restore(sc); + + return is_alive; } /* @@ -132,13 +148,17 @@ void ath_hw_pll_work(struct work_struct *work) u32 pll_sqsum; struct ath_softc *sc = container_of(work, struct ath_softc, hw_pll_work.work); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); /* * ensure that the PLL WAR is executed only * after the STA is associated (or) if the * beaconing had started in interfaces that * uses beacons. */ - if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) + if (!test_bit(ATH_OP_BEACONS, &common->op_flags)) + return; + + if (sc->tx99_state) return; ath9k_ps_wakeup(sc); @@ -152,29 +172,6 @@ void ath_hw_pll_work(struct work_struct *work) } /* - * RX Polling - monitors baseband hangs. - */ -void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon) -{ - if (!AR_SREV_9300(sc->sc_ah)) - return; - - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) - return; - - mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies - (nbeacon * sc->cur_beacon_conf.beacon_interval)); -} - -void ath_rx_poll(unsigned long data) -{ - struct ath_softc *sc = (struct ath_softc *)data; - - if (!test_bit(SC_OP_INVALID, &sc->sc_flags)) - ieee80211_queue_work(sc->hw, &sc->hw_check_work); -} - -/* * PA Pre-distortion. */ static void ath_paprd_activate(struct ath_softc *sc) @@ -184,7 +181,7 @@ static void ath_paprd_activate(struct ath_softc *sc) struct ath9k_hw_cal_data *caldata = ah->caldata; int chain; - if (!caldata || !caldata->paprd_done) { + if (!caldata || !test_bit(PAPRD_DONE, &caldata->cal_flags)) { ath_dbg(common, CALIBRATE, "Failed to activate PAPRD\n"); return; } @@ -208,13 +205,13 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_tx_control txctl; - int time_left; + unsigned long time_left; memset(&txctl, 0, sizeof(txctl)); txctl.txq = sc->tx.txq_map[IEEE80211_AC_BE]; memset(tx_info, 0, sizeof(*tx_info)); - tx_info->band = hw->conf.chandef.chan->band; + tx_info->band = sc->cur_chandef.chan->band; tx_info->flags |= IEEE80211_TX_CTL_NO_ACK; tx_info->control.rates[0].idx = 0; tx_info->control.rates[0].count = 1; @@ -256,7 +253,9 @@ void ath_paprd_calibrate(struct work_struct *work) int len = 1800; int ret; - if (!caldata || !caldata->paprd_packet_sent || caldata->paprd_done) { + if (!caldata || + !test_bit(PAPRD_PACKET_SENT, &caldata->cal_flags) || + test_bit(PAPRD_DONE, &caldata->cal_flags)) { ath_dbg(common, CALIBRATE, "Skipping PAPRD calibration\n"); return; } @@ -316,7 +315,7 @@ void ath_paprd_calibrate(struct work_struct *work) kfree_skb(skb); if (chain_ok) { - caldata->paprd_done = true; + set_bit(PAPRD_DONE, &caldata->cal_flags); ath_paprd_activate(sc); } @@ -331,11 +330,11 @@ fail_paprd: * When the task is complete, it reschedules itself depending on the * appropriate interval that was calculated. */ -void ath_ani_calibrate(unsigned long data) +void ath_ani_calibrate(struct timer_list *t) { - struct ath_softc *sc = (struct ath_softc *)data; + struct ath_common *common = timer_container_of(common, t, ani.timer); + struct ath_softc *sc = common->priv; struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); bool longcal = false; bool shortcal = false; bool aniflag = false; @@ -343,7 +342,7 @@ void ath_ani_calibrate(unsigned long data) u32 cal_interval, short_cal_interval, long_cal_interval; unsigned long flags; - if (ah->caldata && ah->caldata->nfcal_interference) + if (ah->caldata && test_bit(NFCAL_INTF, &ah->caldata->cal_flags)) long_cal_interval = ATH_LONG_CALINTERVAL_INT; else long_cal_interval = ATH_LONG_CALINTERVAL; @@ -405,9 +404,15 @@ void ath_ani_calibrate(unsigned long data) /* Perform calibration if necessary */ if (longcal || shortcal) { - common->ani.caldone = - ath9k_hw_calibrate(ah, ah->curchan, - ah->rxchainmask, longcal); + int ret = ath9k_hw_calibrate(ah, ah->curchan, ah->rxchainmask, + longcal); + if (ret < 0) { + common->ani.caldone = 0; + ath9k_queue_reset(sc, RESET_TYPE_CALIBRATION); + return; + } + + common->ani.caldone = ret; } ath_dbg(common, ANI, @@ -432,7 +437,7 @@ set_timer: mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); if (ar9003_is_paprd_enabled(ah) && ah->caldata) { - if (!ah->caldata->paprd_done) { + if (!test_bit(PAPRD_DONE, &ah->caldata->cal_flags)) { ieee80211_queue_work(sc->hw, &sc->paprd_work); } else if (!ah->paprd_table_write_done) { ath9k_ps_wakeup(sc); @@ -449,8 +454,8 @@ void ath_start_ani(struct ath_softc *sc) unsigned long timestamp = jiffies_to_msecs(jiffies); if (common->disable_ani || - !test_bit(SC_OP_ANI_RUN, &sc->sc_flags) || - (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) + !test_bit(ATH_OP_ANI_RUN, &common->op_flags) || + sc->cur_chan->offchannel) return; common->ani.longcal_timer = timestamp; @@ -467,13 +472,14 @@ void ath_stop_ani(struct ath_softc *sc) struct ath_common *common = ath9k_hw_common(sc->sc_ah); ath_dbg(common, ANI, "Stopping ANI\n"); - del_timer_sync(&common->ani.timer); + timer_delete_sync(&common->ani.timer); } void ath_check_ani(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; /* * Check for the various conditions in which ANI has to @@ -488,23 +494,23 @@ void ath_check_ani(struct ath_softc *sc) * Disable ANI only when there are no * associated stations. */ - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) goto stop_ani; } } else if (ah->opmode == NL80211_IFTYPE_STATION) { - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) goto stop_ani; } - if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags)) { - set_bit(SC_OP_ANI_RUN, &sc->sc_flags); + if (!test_bit(ATH_OP_ANI_RUN, &common->op_flags)) { + set_bit(ATH_OP_ANI_RUN, &common->op_flags); ath_start_ani(sc); } return; stop_ani: - clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); + clear_bit(ATH_OP_ANI_RUN, &common->op_flags); ath_stop_ani(sc); } @@ -516,7 +522,8 @@ void ath_update_survey_nf(struct ath_softc *sc, int channel) if (chan->noisefloor) { survey->filled |= SURVEY_INFO_NOISE_DBM; - survey->noise = ath9k_hw_getchan_noise(ah, chan); + survey->noise = ath9k_hw_getchan_noise(ah, chan, + chan->noisefloor); } } @@ -542,14 +549,14 @@ int ath_update_survey_stats(struct ath_softc *sc) ath_hw_cycle_counters_update(common); if (cc->cycles > 0) { - survey->filled |= SURVEY_INFO_CHANNEL_TIME | - SURVEY_INFO_CHANNEL_TIME_BUSY | - SURVEY_INFO_CHANNEL_TIME_RX | - SURVEY_INFO_CHANNEL_TIME_TX; - survey->channel_time += cc->cycles / div; - survey->channel_time_busy += cc->rx_busy / div; - survey->channel_time_rx += cc->rx_frame / div; - survey->channel_time_tx += cc->tx_frame / div; + survey->filled |= SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_RX | + SURVEY_INFO_TIME_TX; + survey->time += cc->cycles / div; + survey->time_busy += cc->rx_busy / div; + survey->time_rx += cc->rx_frame / div; + survey->time_tx += cc->tx_frame / div; } if (cc->cycles < div) diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 2ef05ebffbcf..b070403e083f 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -311,14 +311,7 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, q = ATH9K_NUM_TX_QUEUES - 3; break; case ATH9K_TX_QUEUE_DATA: - for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++) - if (ah->txq[q].tqi_type == - ATH9K_TX_QUEUE_INACTIVE) - break; - if (q == ATH9K_NUM_TX_QUEUES) { - ath_err(common, "No available TX queue\n"); - return -1; - } + q = qinfo->tqi_subtype; break; default: ath_err(common, "Invalid TX queue type: %u\n", type); @@ -374,7 +367,6 @@ EXPORT_SYMBOL(ath9k_hw_releasetxqueue); bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) { struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_channel *chan = ah->curchan; struct ath9k_tx_queue_info *qi; u32 cwMin, chanCwMin, value; @@ -387,10 +379,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) ath_dbg(common, QUEUE, "Reset TX queue: %u\n", q); if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { - if (chan && IS_CHAN_B(chan)) - chanCwMin = INIT_CWMIN_11B; - else - chanCwMin = INIT_CWMIN; + chanCwMin = INIT_CWMIN; for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1); } else @@ -485,8 +474,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) | AR_Q_MISC_CBR_INCR_DIS0); value = (qi->tqi_readyTime - (ah->config.sw_beacon_response_time - - ah->config.dma_beacon_response_time) - - ah->config.additional_swba_backoff) * 1024; + ah->config.dma_beacon_response_time)) * 1024; REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN); REG_SET_BIT(ah, AR_DMISC(q), @@ -547,32 +535,33 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, rs->rs_status = 0; rs->rs_flags = 0; - rs->flag = 0; + rs->enc_flags = 0; + rs->bw = RATE_INFO_BW_20; rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen; rs->rs_tstamp = ads.AR_RcvTimestamp; if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) { rs->rs_rssi = ATH9K_RSSI_BAD; - rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD; - rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD; - rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD; - rs->rs_rssi_ext0 = ATH9K_RSSI_BAD; - rs->rs_rssi_ext1 = ATH9K_RSSI_BAD; - rs->rs_rssi_ext2 = ATH9K_RSSI_BAD; + rs->rs_rssi_ctl[0] = ATH9K_RSSI_BAD; + rs->rs_rssi_ctl[1] = ATH9K_RSSI_BAD; + rs->rs_rssi_ctl[2] = ATH9K_RSSI_BAD; + rs->rs_rssi_ext[0] = ATH9K_RSSI_BAD; + rs->rs_rssi_ext[1] = ATH9K_RSSI_BAD; + rs->rs_rssi_ext[2] = ATH9K_RSSI_BAD; } else { rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); - rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0, + rs->rs_rssi_ctl[0] = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00); - rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0, + rs->rs_rssi_ctl[1] = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01); - rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0, + rs->rs_rssi_ctl[2] = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02); - rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4, + rs->rs_rssi_ext[0] = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10); - rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4, + rs->rs_rssi_ext[1] = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11); - rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4, + rs->rs_rssi_ext[2] = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12); } if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) @@ -583,21 +572,21 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, rs->rs_rate = MS(ads.ds_rxstatus0, AR_RxRate); rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; + rs->rs_firstaggr = (ads.ds_rxstatus8 & AR_RxFirstAggr) ? 1 : 0; rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; - rs->rs_moreaggr = - (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; + rs->rs_moreaggr = (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); /* directly mapped flags for ieee80211_rx_status */ - rs->flag |= - (ads.ds_rxstatus3 & AR_GI) ? RX_FLAG_SHORT_GI : 0; - rs->flag |= - (ads.ds_rxstatus3 & AR_2040) ? RX_FLAG_40MHZ : 0; + rs->enc_flags |= + (ads.ds_rxstatus3 & AR_GI) ? RX_ENC_FLAG_SHORT_GI : 0; + rs->bw = (ads.ds_rxstatus3 & AR_2040) ? RATE_INFO_BW_40 : + RATE_INFO_BW_20; if (AR_SREV_9280_20_OR_LATER(ah)) - rs->flag |= + rs->enc_flags |= (ads.ds_rxstatus3 & AR_STBC) ? /* we can only Nss=1 STBC */ - (1 << RX_FLAG_STBC_SHIFT) : 0; + (1 << RX_ENC_FLAG_STBC_SHIFT) : 0; if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE; @@ -718,7 +707,7 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset) /* Wait for rx enable bit to go low */ for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) { - if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0) + if ((REG_READ(ah, AR_CR) & AR_CR_RXE(ah)) == 0) break; if (!AR_SREV_9300_20_OR_LATER(ah)) { @@ -773,14 +762,14 @@ bool ath9k_hw_intrpend(struct ath_hw *ah) if (AR_SREV_9100(ah)) return true; - host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE); + host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE(ah)); if (((host_isr & AR_INTR_MAC_IRQ) || (host_isr & AR_INTR_ASYNC_MASK_MCI)) && (host_isr != AR_INTR_SPURIOUS)) return true; - host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE); + host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE(ah)); if ((host_isr & AR_INTR_SYNC_DEFAULT) && (host_isr != AR_INTR_SPURIOUS)) return true; @@ -797,11 +786,11 @@ void ath9k_hw_kill_interrupts(struct ath_hw *ah) REG_WRITE(ah, AR_IER, AR_IER_DISABLE); (void) REG_READ(ah, AR_IER); if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0); - (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE); + REG_WRITE(ah, AR_INTR_ASYNC_ENABLE(ah), 0); + (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE(ah)); - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); - (void) REG_READ(ah, AR_INTR_SYNC_ENABLE); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE(ah), 0); + (void) REG_READ(ah, AR_INTR_SYNC_ENABLE(ah)); } } EXPORT_SYMBOL(ath9k_hw_kill_interrupts); @@ -817,22 +806,14 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_disable_interrupts); -void ath9k_hw_enable_interrupts(struct ath_hw *ah) +static void __ath9k_hw_enable_interrupts(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); u32 sync_default = AR_INTR_SYNC_DEFAULT; u32 async_mask; - if (!(ah->imask & ATH9K_INT_GLOBAL)) - return; - - if (!atomic_inc_and_test(&ah->intr_ref_cnt)) { - ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n", - atomic_read(&ah->intr_ref_cnt)); - return; - } - - if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) || + AR_SREV_9561(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; async_mask = AR_INTR_MAC_IRQ; @@ -843,14 +824,84 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) ath_dbg(common, INTERRUPT, "enable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_ENABLE); if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, async_mask); - REG_WRITE(ah, AR_INTR_ASYNC_MASK, async_mask); + REG_WRITE(ah, AR_INTR_ASYNC_ENABLE(ah), async_mask); + REG_WRITE(ah, AR_INTR_ASYNC_MASK(ah), async_mask); - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default); - REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE(ah), sync_default); + REG_WRITE(ah, AR_INTR_SYNC_MASK(ah), sync_default); } ath_dbg(common, INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); + + if (ah->msi_enabled) { + u32 _msi_reg = 0; + u32 i = 0; + u32 msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64; + + ath_dbg(ath9k_hw_common(ah), INTERRUPT, + "Enabling MSI, msi_mask=0x%X\n", ah->msi_mask); + + REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE(ah), ah->msi_mask); + REG_WRITE(ah, AR_INTR_PRIO_ASYNC_MASK(ah), ah->msi_mask); + ath_dbg(ath9k_hw_common(ah), INTERRUPT, + "AR_INTR_PRIO_ASYNC_ENABLE=0x%X, AR_INTR_PRIO_ASYNC_MASK=0x%X\n", + REG_READ(ah, AR_INTR_PRIO_ASYNC_ENABLE(ah)), + REG_READ(ah, AR_INTR_PRIO_ASYNC_MASK(ah))); + + if (ah->msi_reg == 0) + ah->msi_reg = REG_READ(ah, AR_PCIE_MSI(ah)); + + ath_dbg(ath9k_hw_common(ah), INTERRUPT, + "AR_PCIE_MSI=0x%X, ah->msi_reg = 0x%X\n", + AR_PCIE_MSI(ah), ah->msi_reg); + + i = 0; + do { + REG_WRITE(ah, AR_PCIE_MSI(ah), + (ah->msi_reg | AR_PCIE_MSI_ENABLE) + & msi_pend_addr_mask); + _msi_reg = REG_READ(ah, AR_PCIE_MSI(ah)); + i++; + } while ((_msi_reg & AR_PCIE_MSI_ENABLE) == 0 && i < 200); + + if (i >= 200) + ath_err(ath9k_hw_common(ah), + "%s: _msi_reg = 0x%X\n", + __func__, _msi_reg); + } +} + +void ath9k_hw_resume_interrupts(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!(ah->imask & ATH9K_INT_GLOBAL)) + return; + + if (atomic_read(&ah->intr_ref_cnt) != 0) { + ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n", + atomic_read(&ah->intr_ref_cnt)); + return; + } + + __ath9k_hw_enable_interrupts(ah); +} +EXPORT_SYMBOL(ath9k_hw_resume_interrupts); + +void ath9k_hw_enable_interrupts(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!(ah->imask & ATH9K_INT_GLOBAL)) + return; + + if (!atomic_inc_and_test(&ah->intr_ref_cnt)) { + ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n", + atomic_read(&ah->intr_ref_cnt)); + return; + } + + __ath9k_hw_enable_interrupts(ah); } EXPORT_SYMBOL(ath9k_hw_enable_interrupts); @@ -864,12 +915,21 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah) if (!(ints & ATH9K_INT_GLOBAL)) ath9k_hw_disable_interrupts(ah); + if (ah->msi_enabled) { + ath_dbg(common, INTERRUPT, "Clearing AR_INTR_PRIO_ASYNC_ENABLE\n"); + + REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE(ah), 0); + REG_READ(ah, AR_INTR_PRIO_ASYNC_ENABLE(ah)); + } + ath_dbg(common, INTERRUPT, "New interrupt mask 0x%x\n", ints); mask = ints & ATH9K_INT_COMMON; mask2 = 0; + ah->msi_mask = 0; if (ints & ATH9K_INT_TX) { + ah->msi_mask |= AR_INTR_PRIO_TX; if (ah->config.tx_intr_mitigation) mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM; else { @@ -884,6 +944,7 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah) mask |= AR_IMR_TXEOL; } if (ints & ATH9K_INT_RX) { + ah->msi_mask |= AR_INTR_PRIO_RXLP | AR_INTR_PRIO_RXHP; if (AR_SREV_9300_20_OR_LATER(ah)) { mask |= AR_IMR_RXERR | AR_IMR_RXOK_HP; if (ah->config.rx_intr_mitigation) { @@ -927,11 +988,29 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah) mask2 |= AR_IMR_S2_CST; } + if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) { + if (ints & ATH9K_INT_BB_WATCHDOG) { + mask |= AR_IMR_BCNMISC; + mask2 |= AR_IMR_S2_BB_WATCHDOG; + } + } + ath_dbg(common, INTERRUPT, "new IMR 0x%x\n", mask); REG_WRITE(ah, AR_IMR, mask); - ah->imrs2_reg &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC | - AR_IMR_S2_CABEND | AR_IMR_S2_CABTO | - AR_IMR_S2_TSFOOR | AR_IMR_S2_GTT | AR_IMR_S2_CST); + ah->imrs2_reg &= ~(AR_IMR_S2_TIM | + AR_IMR_S2_DTIM | + AR_IMR_S2_DTIMSYNC | + AR_IMR_S2_CABEND | + AR_IMR_S2_CABTO | + AR_IMR_S2_TSFOOR | + AR_IMR_S2_GTT | + AR_IMR_S2_CST); + + if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) { + if (ints & ATH9K_INT_BB_WATCHDOG) + ah->imrs2_reg &= ~AR_IMR_S2_BB_WATCHDOG; + } + ah->imrs2_reg |= mask2; REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg); @@ -945,3 +1024,25 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah) return; } EXPORT_SYMBOL(ath9k_hw_set_interrupts); + +#define ATH9K_HW_MAX_DCU 10 +#define ATH9K_HW_SLICE_PER_DCU 16 +#define ATH9K_HW_BIT_IN_SLICE 16 +void ath9k_hw_set_tx_filter(struct ath_hw *ah, u8 destidx, bool set) +{ + int dcu_idx; + u32 filter; + + for (dcu_idx = 0; dcu_idx < 10; dcu_idx++) { + filter = SM(set, AR_D_TXBLK_WRITE_COMMAND); + filter |= SM(dcu_idx, AR_D_TXBLK_WRITE_DCU); + filter |= SM((destidx / ATH9K_HW_SLICE_PER_DCU), + AR_D_TXBLK_WRITE_SLICE); + filter |= BIT(destidx % ATH9K_HW_BIT_IN_SLICE); + ath_dbg(ath9k_hw_common(ah), PS, + "DCU%d staid %d set %d txfilter %08x\n", + dcu_idx, destidx, set, filter); + REG_WRITE(ah, AR_D_TXBLK_BASE, filter); + } +} +EXPORT_SYMBOL(ath9k_hw_set_tx_filter); diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index b02dfce964b4..16203e7ecf29 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -16,6 +16,7 @@ #ifndef MAC_H #define MAC_H +#include <net/cfg80211.h> #define set11nTries(_series, _index) \ (SM((_series)[_index].Tries, AR_XmitDataTries##_index)) @@ -34,8 +35,10 @@ |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \ AR_GI##_index : 0) \ |((_series)[_index].RateFlags & ATH9K_RATESERIES_STBC ? \ - AR_STBC##_index : 0) \ - |SM((_series)[_index].ChSel, AR_ChainSel##_index)) + AR_STBC##_index : 0)) + +#define set11nChainSel(_series, _index) \ + (SM((_series)[_index].ChSel, AR_ChainSel##_index)) #define CCK_SIFS_TIME 10 #define CCK_PREAMBLE_BITS 144 @@ -65,10 +68,6 @@ #define INIT_SSH_RETRY 32 #define INIT_SLG_RETRY 32 -#define ATH9K_SLOT_TIME_6 6 -#define ATH9K_SLOT_TIME_9 9 -#define ATH9K_SLOT_TIME_20 20 - #define ATH9K_TXERR_XRETRY 0x01 #define ATH9K_TXERR_FILT 0x02 #define ATH9K_TXERR_FIFO 0x04 @@ -116,11 +115,14 @@ struct ath_tx_status { u8 qid; u16 desc_id; u8 tid; - u32 ba_low; - u32 ba_high; + struct_group(ba, + u32 ba_low; + u32 ba_high; + ); u32 evm0; u32 evm1; u32 evm2; + u32 duration; }; struct ath_rx_status { @@ -133,13 +135,10 @@ struct ath_rx_status { u8 rs_rate; u8 rs_antenna; u8 rs_more; - int8_t rs_rssi_ctl0; - int8_t rs_rssi_ctl1; - int8_t rs_rssi_ctl2; - int8_t rs_rssi_ext0; - int8_t rs_rssi_ext1; - int8_t rs_rssi_ext2; + int8_t rs_rssi_ctl[3]; + int8_t rs_rssi_ext[3]; u8 rs_isaggr; + u8 rs_firstaggr; u8 rs_moreaggr; u8 rs_num_delims; u8 rs_flags; @@ -149,7 +148,8 @@ struct ath_rx_status { u32 evm2; u32 evm3; u32 evm4; - u32 flag; /* see enum mac80211_rx_flags */ + u16 enc_flags; + enum rate_info_bw bw; }; struct ath_htc_rx_status { @@ -158,12 +158,8 @@ struct ath_htc_rx_status { u8 rs_status; u8 rs_phyerr; int8_t rs_rssi; - int8_t rs_rssi_ctl0; - int8_t rs_rssi_ctl1; - int8_t rs_rssi_ctl2; - int8_t rs_rssi_ext0; - int8_t rs_rssi_ext1; - int8_t rs_rssi_ext2; + int8_t rs_rssi_ctl[3]; + int8_t rs_rssi_ext[3]; u8 rs_keyix; u8 rs_rate; u8 rs_antenna; @@ -173,6 +169,7 @@ struct ath_htc_rx_status { u8 rs_num_delims; u8 rs_flags; u8 rs_dummy; + /* FIXME: evm* never used? */ __be32 evm0; __be32 evm1; __be32 evm2; @@ -214,21 +211,25 @@ enum ath9k_phyerr { ATH9K_PHYERR_OFDM_POWER_DROP = 21, ATH9K_PHYERR_OFDM_SERVICE = 22, ATH9K_PHYERR_OFDM_RESTART = 23, - ATH9K_PHYERR_FALSE_RADAR_EXT = 24, + ATH9K_PHYERR_CCK_BLOCKER = 24, ATH9K_PHYERR_CCK_TIMING = 25, ATH9K_PHYERR_CCK_HEADER_CRC = 26, ATH9K_PHYERR_CCK_RATE_ILLEGAL = 27, + ATH9K_PHYERR_CCK_LENGTH_ILLEGAL = 28, + ATH9K_PHYERR_CCK_POWER_DROP = 29, ATH9K_PHYERR_CCK_SERVICE = 30, ATH9K_PHYERR_CCK_RESTART = 31, - ATH9K_PHYERR_CCK_LENGTH_ILLEGAL = 32, - ATH9K_PHYERR_CCK_POWER_DROP = 33, - ATH9K_PHYERR_HT_CRC_ERROR = 34, - ATH9K_PHYERR_HT_LENGTH_ILLEGAL = 35, - ATH9K_PHYERR_HT_RATE_ILLEGAL = 36, + ATH9K_PHYERR_HT_CRC_ERROR = 32, + ATH9K_PHYERR_HT_LENGTH_ILLEGAL = 33, + ATH9K_PHYERR_HT_RATE_ILLEGAL = 34, + ATH9K_PHYERR_HT_ZLF = 35, + + ATH9K_PHYERR_FALSE_RADAR_EXT = 36, + ATH9K_PHYERR_GREEN_FIELD = 37, + ATH9K_PHYERR_SPECTRAL = 38, - ATH9K_PHYERR_SPECTRAL = 38, ATH9K_PHYERR_MAX = 39, }; @@ -250,7 +251,7 @@ struct ath_desc { * when the descriptor is specifically marked to generate * an interrupt with this flag. Descriptors should be * marked periodically to insure timely replenishing of the - * supply needed for sending frames. Defering interrupts + * supply needed for sending frames. Deferring interrupts * reduces system load and potentially allows more concurrent * work to be done but if done to aggressively can cause * senders to backup. When the hardware queue is left too @@ -352,8 +353,14 @@ struct ar5416_desc { #define AR_FrameLen 0x00000fff #define AR_VirtMoreFrag 0x00001000 #define AR_TxCtlRsvd00 0x0000e000 -#define AR_XmitPower 0x003f0000 -#define AR_XmitPower_S 16 +#define AR_XmitPower0 0x003f0000 +#define AR_XmitPower0_S 16 +#define AR_XmitPower1 0x3f000000 +#define AR_XmitPower1_S 24 +#define AR_XmitPower2 0x3f000000 +#define AR_XmitPower2_S 24 +#define AR_XmitPower3 0x3f000000 +#define AR_XmitPower3_S 24 #define AR_RTSEnable 0x00400000 #define AR_VEOL 0x00800000 #define AR_ClrDestMask 0x01000000 @@ -569,6 +576,7 @@ struct ar5416_desc { #define AR_RxAggr 0x00020000 #define AR_PostDelimCRCErr 0x00040000 #define AR_RxStatusRsvd71 0x3ff80000 +#define AR_RxFirstAggr 0x20000000 #define AR_DecryptBusyErr 0x40000000 #define AR_KeyMiss 0x80000000 @@ -601,8 +609,6 @@ enum ath9k_tx_queue_flags { #define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001 #define ATH9K_DECOMP_MASK_SIZE 128 -#define ATH9K_READY_TIME_LO_BOUND 50 -#define ATH9K_READY_TIME_HI_BOUND 96 enum ath9k_pkt_type { ATH9K_PKT_TYPE_NORMAL = 0, @@ -704,7 +710,7 @@ struct ath_tx_info { enum ath9k_pkt_type type; enum ath9k_key_type keytype; u8 keyix; - u8 txpower; + u8 txpower[4]; }; struct ath_hw; @@ -736,6 +742,7 @@ void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning); void ath9k_hw_abortpcurecv(struct ath_hw *ah); bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset); int ath9k_hw_beaconq_setup(struct ath_hw *ah); +void ath9k_hw_set_tx_filter(struct ath_hw *ah, u8 destidx, bool set); /* Interrupt Handling */ bool ath9k_hw_intrpend(struct ath_hw *ah); @@ -743,6 +750,7 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah); void ath9k_hw_enable_interrupts(struct ath_hw *ah); void ath9k_hw_disable_interrupts(struct ath_hw *ah); void ath9k_hw_kill_interrupts(struct ath_hw *ah); +void ath9k_hw_resume_interrupts(struct ath_hw *ah); void ar9002_hw_attach_mac_ops(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 1737a3e33685..740a6fc7b067 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -19,8 +19,8 @@ #include "ath9k.h" #include "btcoex.h" -static void ath9k_set_assoc_state(struct ath_softc *sc, - struct ieee80211_vif *vif); +static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop); u8 ath9k_parse_mpdudensity(u8 mpdudensity) { @@ -57,15 +57,29 @@ u8 ath9k_parse_mpdudensity(u8 mpdudensity) } } -static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq) +static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq, + bool sw_pending) { bool pending = false; spin_lock_bh(&txq->axq_lock); - if (txq->axq_depth || !list_empty(&txq->axq_acq)) + if (txq->axq_depth) { pending = true; + goto out; + } + + if (!sw_pending) + goto out; + + if (txq->mac80211_qnum >= 0) { + struct ath_acq *acq; + acq = &sc->cur_chan->acq[txq->mac80211_qnum]; + if (!list_empty(&acq->acq_new) || !list_empty(&acq->acq_old)) + pending = true; + } +out: spin_unlock_bh(&txq->axq_lock); return pending; } @@ -82,6 +96,23 @@ static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) return ret; } +void ath_ps_full_sleep(struct timer_list *t) +{ + struct ath_softc *sc = timer_container_of(sc, t, sleep_timer); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + unsigned long flags; + bool reset; + + spin_lock_irqsave(&common->cc_lock, flags); + ath_hw_cycle_counters_update(common); + spin_unlock_irqrestore(&common->cc_lock, flags); + + ath9k_hw_setrxabort(sc->sc_ah, 1); + ath9k_hw_stopdmarecv(sc->sc_ah, &reset); + + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); +} + void ath9k_ps_wakeup(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -92,6 +123,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc) if (++sc->ps_usecount != 1) goto unlock; + timer_delete_sync(&sc->sleep_timer); power_mode = sc->sc_ah->power_mode; ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); @@ -103,8 +135,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc) if (power_mode != ATH9K_PM_AWAKE) { spin_lock(&common->cc_lock); ath_hw_cycle_counters_update(common); - memset(&common->cc_survey, 0, sizeof(common->cc_survey)); - memset(&common->cc_ani, 0, sizeof(common->cc_ani)); + memset(&common->cc, 0, sizeof(common->cc)); spin_unlock(&common->cc_lock); } @@ -117,17 +148,17 @@ void ath9k_ps_restore(struct ath_softc *sc) struct ath_common *common = ath9k_hw_common(sc->sc_ah); enum ath9k_power_mode mode; unsigned long flags; - bool reset; spin_lock_irqsave(&sc->sc_pm_lock, flags); if (--sc->ps_usecount != 0) goto unlock; if (sc->ps_idle) { - ath9k_hw_setrxabort(sc->sc_ah, 1); - ath9k_hw_stopdmarecv(sc->sc_ah, &reset); - mode = ATH9K_PM_FULL_SLEEP; - } else if (sc->ps_enabled && + mod_timer(&sc->sleep_timer, jiffies + HZ / 10); + goto unlock; + } + + if (sc->ps_enabled && !(sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA | @@ -153,8 +184,7 @@ void ath9k_ps_restore(struct ath_softc *sc) static void __ath_cancel_work(struct ath_softc *sc) { cancel_work_sync(&sc->paprd_work); - cancel_work_sync(&sc->hw_check_work); - cancel_delayed_work_sync(&sc->tx_complete_work); + cancel_delayed_work_sync(&sc->hw_check_work); cancel_delayed_work_sync(&sc->hw_pll_work); #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT @@ -163,22 +193,21 @@ static void __ath_cancel_work(struct ath_softc *sc) #endif } -static void ath_cancel_work(struct ath_softc *sc) +void ath_cancel_work(struct ath_softc *sc) { __ath_cancel_work(sc); cancel_work_sync(&sc->hw_reset_work); } -static void ath_restart_work(struct ath_softc *sc) +void ath_restart_work(struct ath_softc *sc) { - ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); + ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work, + msecs_to_jiffies(ATH_HW_CHECK_POLL_INT)); - if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9485(sc->sc_ah) || - AR_SREV_9550(sc->sc_ah)) + if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9330(sc->sc_ah)) ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); - ath_start_rx_poll(sc, 3); ath_start_ani(sc); } @@ -188,18 +217,16 @@ static bool ath_prepare_reset(struct ath_softc *sc) bool ret = true; ieee80211_stop_queues(sc->hw); - - sc->hw_busy_count = 0; ath_stop_ani(sc); - del_timer_sync(&sc->rx_poll_timer); - ath9k_hw_disable_interrupts(ah); - if (!ath_drain_all_txq(sc)) - ret = false; - - if (!ath_stoprecv(sc)) - ret = false; + if (AR_SREV_9300_20_OR_LATER(ah)) { + ret &= ath_stoprecv(sc); + ret &= ath_drain_all_txq(sc); + } else { + ret &= ath_drain_all_txq(sc); + ret &= ath_stoprecv(sc); + } return ret; } @@ -210,24 +237,28 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) struct ath_common *common = ath9k_hw_common(ah); unsigned long flags; - if (ath_startrecv(sc) != 0) { - ath_err(common, "Unable to restart recv logic\n"); - return false; - } + ath9k_calculate_summary_state(sc, sc->cur_chan); + ath_startrecv(sc); + ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, + sc->cur_chan->txpower, + &sc->cur_chan->cur_txpower); + clear_bit(ATH_OP_HW_RESET, &common->op_flags); - ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->config.txpowlimit, &sc->curtxpow); + if (!sc->cur_chan->offchannel && start) { + /* restore per chanctx TSF timer */ + if (sc->cur_chan->tsf_val) { + u32 offset; + + offset = ath9k_hw_get_tsf_offset(sc->cur_chan->tsf_ts, 0); + ath9k_hw_settsf64(ah, sc->cur_chan->tsf_val + offset); + } - clear_bit(SC_OP_HW_RESET, &sc->sc_flags); - ath9k_hw_set_interrupts(ah); - ath9k_hw_enable_interrupts(ah); - if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && start) { - if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) + if (!test_bit(ATH_OP_BEACONS, &common->op_flags)) goto work; if (ah->opmode == NL80211_IFTYPE_STATION && - test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { spin_lock_irqsave(&sc->sc_pm_lock, flags); sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; spin_unlock_irqrestore(&sc->sc_pm_lock, flags); @@ -236,12 +267,15 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) } work: ath_restart_work(sc); + ath_txq_schedule_all(sc); } - if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) - ath_ant_comb_update(sc); + sc->gtt_cnt = 0; + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); ieee80211_wake_queues(sc->hw); + ath9k_p2p_ps_timer(sc); return true; } @@ -256,12 +290,14 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) __ath_cancel_work(sc); + disable_irq(sc->irq); tasklet_disable(&sc->intr_tq); + tasklet_disable(&sc->bcon_tasklet); spin_lock_bh(&sc->sc_pcu_lock); - if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) { + if (!sc->cur_chan->offchannel) { fastcc = false; - caldata = &sc->caldata; + caldata = &sc->cur_chan->caldata; } if (!hchan) { @@ -269,9 +305,21 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) hchan = ah->curchan; } + if (!hchan) { + fastcc = false; + hchan = ath9k_cmn_get_channel(sc->hw, ah, &sc->cur_chan->chandef); + } + if (!ath_prepare_reset(sc)) fastcc = false; + if (ath9k_is_chanctx_enabled()) + fastcc = false; + + spin_lock_bh(&sc->chan_lock); + sc->cur_chandef = sc->cur_chan->chandef; + spin_unlock_bh(&sc->chan_lock); + ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", hchan->channel, IS_CHAN_HT40(hchan), fastcc); @@ -287,38 +335,21 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) } if (ath9k_hw_mci_is_enabled(sc->sc_ah) && - (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) + sc->cur_chan->offchannel) ath9k_mci_set_txpower(sc, true, false); if (!ath_complete_reset(sc, true)) r = -EIO; out: + enable_irq(sc->irq); spin_unlock_bh(&sc->sc_pcu_lock); + tasklet_enable(&sc->bcon_tasklet); tasklet_enable(&sc->intr_tq); return r; } - -/* - * Set/change channels. If the channel is really being changed, it's done - * by reseting the chip. To accomplish this we must first cleanup any pending - * DMA, then restart stuff. -*/ -static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, - struct ath9k_channel *hchan) -{ - int r; - - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) - return -EIO; - - r = ath_reset_internal(sc, hchan); - - return r; -} - static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, struct ieee80211_vif *vif) { @@ -328,45 +359,73 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, an->sc = sc; an->sta = sta; an->vif = vif; + memset(&an->key_idx, 0, sizeof(an->key_idx)); ath_tx_node_init(sc, an); - if (sta->ht_cap.ht_supported) { - an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + - sta->ht_cap.ampdu_factor); - an->mpdudensity = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); - } + ath_dynack_node_init(sc->sc_ah, an); } static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) { struct ath_node *an = (struct ath_node *)sta->drv_priv; ath_tx_node_cleanup(sc, an); + + ath_dynack_node_deinit(sc->sc_ah, an); } -void ath9k_tasklet(unsigned long data) +void ath9k_tasklet(struct tasklet_struct *t) { - struct ath_softc *sc = (struct ath_softc *)data; + struct ath_softc *sc = from_tasklet(sc, t, intr_tq); struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); enum ath_reset_type type; unsigned long flags; - u32 status = sc->intrstatus; + u32 status; u32 rxmask; + spin_lock_irqsave(&sc->intr_lock, flags); + status = sc->intrstatus; + sc->intrstatus = 0; + spin_unlock_irqrestore(&sc->intr_lock, flags); + ath9k_ps_wakeup(sc); spin_lock(&sc->sc_pcu_lock); - if ((status & ATH9K_INT_FATAL) || + if (status & ATH9K_INT_FATAL) { + type = RESET_TYPE_FATAL_INT; + ath9k_queue_reset(sc, type); + ath_dbg(common, RESET, "FATAL: Skipping interrupts\n"); + goto out; + } + + if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) && (status & ATH9K_INT_BB_WATCHDOG)) { + spin_lock_irqsave(&common->cc_lock, flags); + ath_hw_cycle_counters_update(common); + ar9003_hw_bb_watchdog_dbg_info(ah); + spin_unlock_irqrestore(&common->cc_lock, flags); - if (status & ATH9K_INT_FATAL) - type = RESET_TYPE_FATAL_INT; - else + if (ar9003_hw_bb_watchdog_check(ah)) { type = RESET_TYPE_BB_WATCHDOG; + ath9k_queue_reset(sc, type); - ath9k_queue_reset(sc, type); - goto out; + ath_dbg(common, RESET, + "BB_WATCHDOG: Skipping interrupts\n"); + goto out; + } + } + + if (status & ATH9K_INT_GTT) { + sc->gtt_cnt++; + + if ((sc->gtt_cnt >= MAX_GTT_CNT) && !ath9k_hw_check_alive(ah)) { + type = RESET_TYPE_TX_GTT; + ath9k_queue_reset(sc, type); + ath_dbg(common, RESET, + "GTT: Skipping interrupts\n"); + goto out; + } } spin_lock_irqsave(&sc->sc_pm_lock, flags); @@ -393,21 +452,35 @@ void ath9k_tasklet(unsigned long data) ath_rx_tasklet(sc, 0, true); ath_rx_tasklet(sc, 0, false); + sc->rx_active_count++; } if (status & ATH9K_INT_TX) { - if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + /* + * For EDMA chips, TX completion is enabled for the + * beacon queue, so if a beacon has been transmitted + * successfully after a GTT interrupt, the GTT counter + * gets reset to zero here. + */ + sc->gtt_cnt = 0; + ath_tx_edma_tasklet(sc); - else + } else { ath_tx_tasklet(sc); + } + + wake_up(&sc->tx_wait); } + if (status & ATH9K_INT_GENTIMER) + ath_gen_timer_isr(sc->sc_ah); + ath9k_btcoex_handle_interrupt(sc, status); -out: /* re-enable hardware interrupt */ - ath9k_hw_enable_interrupts(ah); - + ath9k_hw_resume_interrupts(ah); +out: spin_unlock(&sc->sc_pcu_lock); ath9k_ps_restore(sc); } @@ -425,6 +498,7 @@ irqreturn_t ath_isr(int irq, void *dev) ATH9K_INT_TX | \ ATH9K_INT_BMISS | \ ATH9K_INT_CST | \ + ATH9K_INT_GTT | \ ATH9K_INT_TSFOOR | \ ATH9K_INT_GENTIMER | \ ATH9K_INT_MCI) @@ -433,6 +507,7 @@ irqreturn_t ath_isr(int irq, void *dev) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); enum ath9k_int status; + u32 sync_cause = 0; bool sched = false; /* @@ -440,28 +515,28 @@ irqreturn_t ath_isr(int irq, void *dev) * touch anything. Note this can happen early * on if the IRQ is shared. */ - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) + if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags)) return IRQ_NONE; /* shared irq, not for us */ - if (!ath9k_hw_intrpend(ah)) return IRQ_NONE; - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) { - ath9k_hw_kill_interrupts(ah); - return IRQ_HANDLED; - } - /* * 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. */ - ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ + ath9k_hw_getisr(ah, &status, &sync_cause); /* NB: clears ISR too */ + ath9k_debug_sync_cause(sc, sync_cause); status &= ah->imask; /* discard unasked-for bits */ + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) { + ath9k_hw_kill_interrupts(sc->sc_ah); + return IRQ_HANDLED; + } + /* * If there are no status bits set, then this interrupt was not * for me (should have been caught above). @@ -470,38 +545,24 @@ irqreturn_t ath_isr(int irq, void *dev) return IRQ_NONE; /* Cache the status */ - sc->intrstatus = status; + spin_lock(&sc->intr_lock); + sc->intrstatus |= status; + spin_unlock(&sc->intr_lock); if (status & SCHED_INTR) sched = true; /* - * If a FATAL or RXORN interrupt is received, we have to reset the - * chip immediately. + * If a FATAL interrupt is received, we have to reset the chip + * immediately. */ - if ((status & ATH9K_INT_FATAL) || ((status & ATH9K_INT_RXORN) && - !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA))) + if (status & ATH9K_INT_FATAL) goto chip_reset; - if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && - (status & ATH9K_INT_BB_WATCHDOG)) { - - spin_lock(&common->cc_lock); - ath_hw_cycle_counters_update(common); - ar9003_hw_bb_watchdog_dbg_info(ah); - spin_unlock(&common->cc_lock); - + if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) && + (status & ATH9K_INT_BB_WATCHDOG)) goto chip_reset; - } -#ifdef CONFIG_PM_SLEEP - if (status & ATH9K_INT_BMISS) { - if (atomic_read(&sc->wow_sleep_proc_intr) == 0) { - ath_dbg(common, ANY, "during WoW we got a BMISS\n"); - atomic_inc(&sc->wow_got_bmiss_intr); - atomic_dec(&sc->wow_sleep_proc_intr); - } - } -#endif + if (status & ATH9K_INT_SWBA) tasklet_schedule(&sc->bcon_tasklet); @@ -532,7 +593,7 @@ chip_reset: if (sched) { /* turn off every interrupt */ - ath9k_hw_disable_interrupts(ah); + ath9k_hw_kill_interrupts(ah); tasklet_schedule(&sc->intr_tq); } @@ -541,34 +602,38 @@ chip_reset: #undef SCHED_INTR } -static int ath_reset(struct ath_softc *sc) +/* + * This function is called when a HW reset cannot be deferred + * and has to be immediate. + */ +int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan) { - int i, r; - - ath9k_ps_wakeup(sc); - - r = ath_reset_internal(sc, NULL); - - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (!ATH_TXQ_SETUP(sc, i)) - continue; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + int r; - spin_lock_bh(&sc->tx.txq[i].axq_lock); - ath_txq_schedule(sc, &sc->tx.txq[i]); - spin_unlock_bh(&sc->tx.txq[i].axq_lock); - } + ath9k_hw_kill_interrupts(sc->sc_ah); + set_bit(ATH_OP_HW_RESET, &common->op_flags); + ath9k_ps_wakeup(sc); + r = ath_reset_internal(sc, hchan); ath9k_ps_restore(sc); return r; } +/* + * When a HW reset can be deferred, it is added to the + * hw_reset_work workqueue, but we set ATH_OP_HW_RESET before + * queueing. + */ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); #ifdef CONFIG_ATH9K_DEBUGFS RESET_STAT_INC(sc, type); #endif - set_bit(SC_OP_HW_RESET, &sc->sc_flags); + ath9k_hw_kill_interrupts(sc->sc_ah); + set_bit(ATH_OP_HW_RESET, &common->op_flags); ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } @@ -576,7 +641,9 @@ void ath_reset_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work); - ath_reset(sc); + ath9k_ps_wakeup(sc); + ath_reset_internal(sc, NULL); + ath9k_ps_restore(sc); } /**********************/ @@ -588,7 +655,8 @@ static int ath9k_start(struct ieee80211_hw *hw) struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_channel *curchan = hw->conf.chandef.chan; + struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan; + struct ath_chanctx *ctx = sc->cur_chan; struct ath9k_channel *init_channel; int r; @@ -599,7 +667,8 @@ static int ath9k_start(struct ieee80211_hw *hw) ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); - init_channel = ath9k_cmn_get_curchannel(hw, ah); + init_channel = ath9k_cmn_get_channel(hw, ah, &ctx->chandef); + sc->cur_chandef = hw->conf.chandef; /* Reset SERDES registers */ ath9k_hw_configpcipowersave(ah, false); @@ -630,28 +699,36 @@ static int ath9k_start(struct ieee80211_hw *hw) if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ah->imask |= ATH9K_INT_RXHP | - ATH9K_INT_RXLP | - ATH9K_INT_BB_WATCHDOG; + ATH9K_INT_RXLP; else ah->imask |= ATH9K_INT_RX; - ah->imask |= ATH9K_INT_GTT; + if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) + ah->imask |= ATH9K_INT_BB_WATCHDOG; + + /* + * Enable GTT interrupts only for AR9003/AR9004 chips + * for now. + */ + if (AR_SREV_9300_20_OR_LATER(ah)) + ah->imask |= ATH9K_INT_GTT; if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) ah->imask |= ATH9K_INT_CST; ath_mci_enable(sc); - clear_bit(SC_OP_INVALID, &sc->sc_flags); + clear_bit(ATH_OP_INVALID, &common->op_flags); sc->sc_ah->is_monitoring = false; if (!ath_complete_reset(sc, false)) ah->reset_power_on = false; if (ah->led_pin >= 0) { - ath9k_hw_cfg_output(ah, ah->led_pin, - AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - ath9k_hw_set_gpio(ah, ah->led_pin, 0); + ath9k_hw_set_gpio(ah, ah->led_pin, + (ah->config.led_active_high) ? 1 : 0); + ath9k_hw_gpio_request_out(ah, ah->led_pin, NULL, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); } /* @@ -660,8 +737,12 @@ static int ath9k_start(struct ieee80211_hw *hw) */ ath9k_cmn_init_crypto(sc->sc_ah); + ath9k_hw_reset_tsf(ah); + spin_unlock_bh(&sc->sc_pcu_lock); + ath9k_rng_start(sc); + mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); @@ -737,7 +818,7 @@ static void ath9k_tx(struct ieee80211_hw *hw, if (ath_tx_start(hw, skb, &txctl) != 0) { ath_dbg(common, XMIT, "TX failed\n"); - TX_STAT_INC(txctl.txq->axq_qnum, txfailed); + TX_STAT_INC(sc, txctl.txq->axq_qnum, txfailed); goto exit; } @@ -746,19 +827,91 @@ exit: ieee80211_free_txskb(hw, skb); } -static void ath9k_stop(struct ieee80211_hw *hw) +static bool ath9k_txq_list_has_key(struct list_head *txq_list, u32 keyix) +{ + struct ath_buf *bf; + struct ieee80211_tx_info *txinfo; + struct ath_frame_info *fi; + + list_for_each_entry(bf, txq_list, list) { + if (bf->bf_state.stale || !bf->bf_mpdu) + continue; + + txinfo = IEEE80211_SKB_CB(bf->bf_mpdu); + fi = (struct ath_frame_info *)&txinfo->status.status_driver_data[0]; + if (fi->keyix == keyix) + return true; + } + + return false; +} + +static bool ath9k_txq_has_key(struct ath_softc *sc, u32 keyix) +{ + struct ath_hw *ah = sc->sc_ah; + int i, j; + struct ath_txq *txq; + bool key_in_use = false; + + for (i = 0; !key_in_use && i < ATH9K_NUM_TX_QUEUES; i++) { + if (!ATH_TXQ_SETUP(sc, i)) + continue; + txq = &sc->tx.txq[i]; + if (!txq->axq_depth) + continue; + if (!ath9k_hw_numtxpending(ah, txq->axq_qnum)) + continue; + + ath_txq_lock(sc, txq); + key_in_use = ath9k_txq_list_has_key(&txq->axq_q, keyix); + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { + int idx = txq->txq_tailidx; + + for (j = 0; !key_in_use && + !list_empty(&txq->txq_fifo[idx]) && + j < ATH_TXFIFO_DEPTH; j++) { + key_in_use = ath9k_txq_list_has_key( + &txq->txq_fifo[idx], keyix); + INCR(idx, ATH_TXFIFO_DEPTH); + } + } + ath_txq_unlock(sc, txq); + } + + return key_in_use; +} + +static void ath9k_pending_key_del(struct ath_softc *sc, u8 keyix) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + + if (!test_bit(keyix, ah->pending_del_keymap) || + ath9k_txq_has_key(sc, keyix)) + return; + + /* No more TXQ frames point to this key cache entry, so delete it. */ + clear_bit(keyix, ah->pending_del_keymap); + ath_key_delete(common, keyix); +} + +static void ath9k_stop(struct ieee80211_hw *hw, bool suspend) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); bool prev_idle; + int i; + + ath9k_deinit_channel_context(sc); mutex_lock(&sc->mutex); + ath9k_rng_stop(sc); + ath_cancel_work(sc); - del_timer_sync(&sc->rx_poll_timer); - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); mutex_unlock(&sc->mutex); return; @@ -790,8 +943,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) spin_lock_bh(&sc->sc_pcu_lock); if (ah->led_pin >= 0) { - ath9k_hw_set_gpio(ah, ah->led_pin, 1); - ath9k_hw_cfg_gpio_input(ah, ah->led_pin); + ath9k_hw_set_gpio(ah, ah->led_pin, + (ah->config.led_active_high) ? 0 : 1); + ath9k_hw_gpio_request_in(ah, ah->led_pin, NULL); } ath_prepare_reset(sc); @@ -802,18 +956,29 @@ static void ath9k_stop(struct ieee80211_hw *hw) } if (!ah->curchan) - ah->curchan = ath9k_cmn_get_curchannel(hw, ah); + ah->curchan = ath9k_cmn_get_channel(hw, ah, + &sc->cur_chan->chandef); ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); + + set_bit(ATH_OP_INVALID, &common->op_flags); + ath9k_hw_phy_disable(ah); ath9k_hw_configpcipowersave(ah, true); spin_unlock_bh(&sc->sc_pcu_lock); + for (i = 0; i < ATH_KEYMAX; i++) + ath9k_pending_key_del(sc, i); + + /* Clear key cache entries explicitly to get rid of any potentially + * remaining keys. + */ + ath9k_cmn_init_crypto(sc->sc_ah); + ath9k_ps_restore(sc); - set_bit(SC_OP_INVALID, &sc->sc_flags); sc->ps_idle = prev_idle; mutex_unlock(&sc->mutex); @@ -821,7 +986,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath_dbg(common, CONFIG, "Driver halt\n"); } -bool ath9k_uses_beacons(int type) +static bool ath9k_uses_beacons(int type) { switch (type) { case NL80211_IFTYPE_AP: @@ -833,9 +998,26 @@ bool ath9k_uses_beacons(int type) } } -static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +static void ath9k_vif_iter_set_beacon(struct ath9k_vif_iter_data *iter_data, + struct ieee80211_vif *vif) { - struct ath9k_vif_iter_data *iter_data = data; + /* Use the first (configured) interface, but preferring AP interfaces. */ + if (!iter_data->primary_beacon_vif) { + iter_data->primary_beacon_vif = vif; + } else { + if (iter_data->primary_beacon_vif->type != NL80211_IFTYPE_AP && + vif->type == NL80211_IFTYPE_AP) + iter_data->primary_beacon_vif = vif; + } + + iter_data->beacons = true; + iter_data->nbcnvifs += 1; +} + +static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data, + u8 *mac, struct ieee80211_vif *vif) +{ + struct ath_vif *avp = (struct ath_vif *)vif->drv_priv; int i; if (iter_data->has_hw_macaddr) { @@ -847,77 +1029,177 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) iter_data->has_hw_macaddr = true; } + if (!vif->bss_conf.use_short_slot) + iter_data->slottime = 20; + switch (vif->type) { case NL80211_IFTYPE_AP: iter_data->naps++; + if (vif->bss_conf.enable_beacon) + ath9k_vif_iter_set_beacon(iter_data, vif); break; case NL80211_IFTYPE_STATION: iter_data->nstations++; + if (avp->assoc && !iter_data->primary_sta) + iter_data->primary_sta = vif; + break; + case NL80211_IFTYPE_OCB: + iter_data->nocbs++; break; case NL80211_IFTYPE_ADHOC: iter_data->nadhocs++; + if (vif->bss_conf.enable_beacon) + ath9k_vif_iter_set_beacon(iter_data, vif); break; case NL80211_IFTYPE_MESH_POINT: iter_data->nmeshes++; - break; - case NL80211_IFTYPE_WDS: - iter_data->nwds++; + if (vif->bss_conf.enable_beacon) + ath9k_vif_iter_set_beacon(iter_data, vif); break; default: break; } } -static void ath9k_sta_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +static void ath9k_update_bssid_mask(struct ath_softc *sc, + struct ath_chanctx *ctx, + struct ath9k_vif_iter_data *iter_data) { - struct ath_softc *sc = data; - struct ath_vif *avp = (void *)vif->drv_priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_vif *avp; + int i; - if (vif->type != NL80211_IFTYPE_STATION) + if (!ath9k_is_chanctx_enabled()) return; - if (avp->primary_sta_vif) - ath9k_set_assoc_state(sc, vif); + list_for_each_entry(avp, &ctx->vifs, list) { + if (ctx->nvifs_assigned != 1) + continue; + + if (!iter_data->has_hw_macaddr) + continue; + + ether_addr_copy(common->curbssid, avp->bssid); + + /* perm_addr will be used as the p2p device address. */ + for (i = 0; i < ETH_ALEN; i++) + iter_data->mask[i] &= + ~(iter_data->hw_macaddr[i] ^ + sc->hw->wiphy->perm_addr[i]); + } } /* Called with sc->mutex held. */ -void ath9k_calculate_iter_data(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, +void ath9k_calculate_iter_data(struct ath_softc *sc, + struct ath_chanctx *ctx, struct ath9k_vif_iter_data *iter_data) { - struct ath_softc *sc = hw->priv; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); + struct ath_vif *avp; /* - * Use the hardware MAC address as reference, the hardware uses it - * together with the BSSID mask when matching addresses. + * The hardware will use primary station addr together with the + * BSSID mask when matching addresses. */ memset(iter_data, 0, sizeof(*iter_data)); - memset(&iter_data->mask, 0xff, ETH_ALEN); + eth_broadcast_addr(iter_data->mask); + iter_data->slottime = 9; + + list_for_each_entry(avp, &ctx->vifs, list) + ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif); + + ath9k_update_bssid_mask(sc, ctx, iter_data); +} + +static void ath9k_set_assoc_state(struct ath_softc *sc, + struct ieee80211_vif *vif, bool changed) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_vif *avp = (struct ath_vif *)vif->drv_priv; + unsigned long flags; + + set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); - if (vif) - ath9k_vif_iter(iter_data, vif->addr, vif); + ether_addr_copy(common->curbssid, avp->bssid); + common->curaid = avp->aid; + ath9k_hw_write_associd(sc->sc_ah); - /* Get list of all active MAC addresses */ - ieee80211_iterate_active_interfaces_atomic( - sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - ath9k_vif_iter, iter_data); + if (changed) { + common->last_rssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; - memcpy(common->macaddr, iter_data->hw_macaddr, ETH_ALEN); + spin_lock_irqsave(&sc->sc_pm_lock, flags); + sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); + } + + if (ath9k_hw_mci_is_enabled(sc->sc_ah)) + ath9k_mci_update_wlan_channels(sc, false); + + ath_dbg(common, CONFIG, + "Primary Station interface: %pM, BSSID: %pM\n", + vif->addr, common->curbssid); } +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT +static void ath9k_set_offchannel_state(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_vif *vif = NULL; + + ath9k_ps_wakeup(sc); + + if (sc->offchannel.state < ATH_OFFCHANNEL_ROC_START) + vif = sc->offchannel.scan_vif; + else + vif = sc->offchannel.roc_vif; + + if (WARN_ON(!vif)) + goto exit; + + eth_zero_addr(common->curbssid); + eth_broadcast_addr(common->bssidmask); + memcpy(common->macaddr, vif->addr, ETH_ALEN); + common->curaid = 0; + ah->opmode = vif->type; + ah->imask &= ~ATH9K_INT_SWBA; + ah->imask &= ~ATH9K_INT_TSFOOR; + ah->slottime = 9; + + ath_hw_setbssidmask(common); + ath9k_hw_setopmode(ah); + ath9k_hw_write_associd(sc->sc_ah); + ath9k_hw_set_interrupts(ah); + ath9k_hw_init_global_settings(ah); + +exit: + ath9k_ps_restore(sc); +} +#endif + /* Called with sc->mutex held. */ -static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +void ath9k_calculate_summary_state(struct ath_softc *sc, + struct ath_chanctx *ctx) { - struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_vif_iter_data iter_data; - enum nl80211_iftype old_opmode = ah->opmode; - ath9k_calculate_iter_data(hw, vif, &iter_data); + ath_chanctx_check_active(sc, ctx); + + if (ctx != sc->cur_chan) + return; + +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + if (ctx == &sc->offchannel.chan) + return ath9k_set_offchannel_state(sc); +#endif + + ath9k_ps_wakeup(sc); + ath9k_calculate_iter_data(sc, ctx, &iter_data); + + if (iter_data.has_hw_macaddr) + memcpy(common->macaddr, iter_data.hw_macaddr, ETH_ALEN); memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); ath_hw_setbssidmask(common); @@ -927,11 +1209,13 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ah->opmode = NL80211_IFTYPE_AP; } else { ath9k_hw_set_tsfadjust(ah, false); + if (iter_data.beacons) + ath9k_beacon_ensure_primary_slot(sc); if (iter_data.nmeshes) ah->opmode = NL80211_IFTYPE_MESH_POINT; - else if (iter_data.nwds) - ah->opmode = NL80211_IFTYPE_AP; + else if (iter_data.nocbs) + ah->opmode = NL80211_IFTYPE_OCB; else if (iter_data.nadhocs) ah->opmode = NL80211_IFTYPE_ADHOC; else @@ -940,24 +1224,106 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ath9k_hw_setopmode(ah); + ctx->switch_after_beacon = false; if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) ah->imask |= ATH9K_INT_TSFOOR; - else + else { ah->imask &= ~ATH9K_INT_TSFOOR; + if (iter_data.naps == 1 && iter_data.beacons) + ctx->switch_after_beacon = true; + } + + if (ah->opmode == NL80211_IFTYPE_STATION) { + bool changed = (iter_data.primary_sta != ctx->primary_sta); + if (iter_data.primary_sta) { + iter_data.primary_beacon_vif = iter_data.primary_sta; + iter_data.beacons = true; + ath9k_set_assoc_state(sc, iter_data.primary_sta, + changed); + ctx->primary_sta = iter_data.primary_sta; + } else { + ctx->primary_sta = NULL; + eth_zero_addr(common->curbssid); + common->curaid = 0; + ath9k_hw_write_associd(sc->sc_ah); + if (ath9k_hw_mci_is_enabled(sc->sc_ah)) + ath9k_mci_update_wlan_channels(sc, true); + } + } + sc->nbcnvifs = iter_data.nbcnvifs; + ath9k_beacon_config(sc, iter_data.primary_beacon_vif, + iter_data.beacons); ath9k_hw_set_interrupts(ah); - /* - * If we are changing the opmode to STATION, - * a beacon sync needs to be done. - */ - if (ah->opmode == NL80211_IFTYPE_STATION && - old_opmode == NL80211_IFTYPE_AP && - test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + if (ah->slottime != iter_data.slottime) { + ah->slottime = iter_data.slottime; + ath9k_hw_init_global_settings(ah); + } + + if (iter_data.primary_sta) + set_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); + else + clear_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags); + + ath_dbg(common, CONFIG, + "macaddr: %pM, bssid: %pM, bssidmask: %pM\n", + common->macaddr, common->curbssid, common->bssidmask); + + ath9k_ps_restore(sc); +} + +static void ath9k_tpc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + int *power = data; + + if (vif->bss_conf.txpower == INT_MIN) + return; + + if (*power < vif->bss_conf.txpower) + *power = vif->bss_conf.txpower; +} + +/* Called with sc->mutex held. */ +void ath9k_set_txpower(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + int power; + struct ath_hw *ah = sc->sc_ah; + struct ath_regulatory *reg = ath9k_hw_regulatory(ah); + + ath9k_ps_wakeup(sc); + if (ah->tpc_enabled) { + power = (vif) ? vif->bss_conf.txpower : -1; ieee80211_iterate_active_interfaces_atomic( - sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - ath9k_sta_vif_iter, sc); + sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + ath9k_tpc_vif_iter, &power); + if (power == -1) + power = sc->hw->conf.power_level; + } else { + power = sc->hw->conf.power_level; } + sc->cur_chan->txpower = 2 * power; + ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); + sc->cur_chan->cur_txpower = reg->max_power_level; + ath9k_ps_restore(sc); +} + +static void ath9k_assign_hw_queues(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + int i; + + if (!ath9k_is_chanctx_enabled()) + return; + + for (i = 0; i < IEEE80211_NUM_ACS; i++) + vif->hw_queue[i] = i; + + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_MESH_POINT) + vif->cab_queue = hw->queues - 2; + else + vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; } static int ath9k_add_interface(struct ieee80211_hw *hw, @@ -966,19 +1332,45 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); + struct ath_vif *avp = (void *)vif->drv_priv; + struct ath_node *an = &avp->mcast_node; mutex_lock(&sc->mutex); + if (IS_ENABLED(CONFIG_ATH9K_TX99)) { + if (sc->cur_chan->nvifs >= 1) { + mutex_unlock(&sc->mutex); + return -EOPNOTSUPP; + } + sc->tx99_vif = vif; + } ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type); - sc->nvifs++; + sc->cur_chan->nvifs++; - ath9k_ps_wakeup(sc); - ath9k_calculate_summary_state(hw, vif); - ath9k_ps_restore(sc); + if (vif->type == NL80211_IFTYPE_STATION && ath9k_is_chanctx_enabled()) + vif->driver_flags |= IEEE80211_VIF_GET_NOA_UPDATE; if (ath9k_uses_beacons(vif->type)) ath9k_beacon_assign_slot(sc, vif); + avp->vif = vif; + if (!ath9k_is_chanctx_enabled()) { + avp->chanctx = sc->cur_chan; + list_add_tail(&avp->list, &avp->chanctx->vifs); + } + + ath9k_calculate_summary_state(sc, avp->chanctx); + + ath9k_assign_hw_queues(hw, vif); + + ath9k_set_txpower(sc, vif); + + an->sc = sc; + an->sta = NULL; + an->vif = vif; + an->no_ps_filter = true; + ath_tx_node_init(sc, an); + mutex_unlock(&sc->mutex); return 0; } @@ -990,23 +1382,31 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_vif *avp = (void *)vif->drv_priv; - ath_dbg(common, CONFIG, "Change Interface\n"); mutex_lock(&sc->mutex); + if (IS_ENABLED(CONFIG_ATH9K_TX99)) { + mutex_unlock(&sc->mutex); + return -EOPNOTSUPP; + } + + ath_dbg(common, CONFIG, "Change Interface\n"); + if (ath9k_uses_beacons(vif->type)) ath9k_beacon_remove_slot(sc, vif); vif->type = new_type; vif->p2p = p2p; - ath9k_ps_wakeup(sc); - ath9k_calculate_summary_state(hw, vif); - ath9k_ps_restore(sc); - if (ath9k_uses_beacons(vif->type)) ath9k_beacon_assign_slot(sc, vif); + ath9k_assign_hw_queues(hw, vif); + ath9k_calculate_summary_state(sc, avp->chanctx); + + ath9k_set_txpower(sc, vif); + mutex_unlock(&sc->mutex); return 0; } @@ -1016,19 +1416,27 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_vif *avp = (void *)vif->drv_priv; ath_dbg(common, CONFIG, "Detach Interface\n"); mutex_lock(&sc->mutex); - sc->nvifs--; + ath9k_p2p_remove_vif(sc, vif); + + sc->cur_chan->nvifs--; + sc->tx99_vif = NULL; + if (!ath9k_is_chanctx_enabled()) + list_del(&avp->list); if (ath9k_uses_beacons(vif->type)) ath9k_beacon_remove_slot(sc, vif); - ath9k_ps_wakeup(sc); - ath9k_calculate_summary_state(hw, NULL); - ath9k_ps_restore(sc); + ath_tx_node_cleanup(sc, &avp->mcast_node); + + ath9k_calculate_summary_state(sc, avp->chanctx); + + ath9k_set_txpower(sc, NULL); mutex_unlock(&sc->mutex); } @@ -1038,6 +1446,9 @@ static void ath9k_enable_ps(struct ath_softc *sc) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); + if (IS_ENABLED(CONFIG_ATH9K_TX99)) + return; + sc->ps_enabled = true; if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) { @@ -1054,6 +1465,9 @@ static void ath9k_disable_ps(struct ath_softc *sc) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); + if (IS_ENABLED(CONFIG_ATH9K_TX99)) + return; + sc->ps_enabled = false; ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { @@ -1070,82 +1484,13 @@ static void ath9k_disable_ps(struct ath_softc *sc) ath_dbg(common, PS, "PowerSave disabled\n"); } -void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw) -{ - struct ath_softc *sc = hw->priv; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u32 rxfilter; - - if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { - ath_err(common, "spectrum analyzer not implemented on this hardware\n"); - return; - } - - ath9k_ps_wakeup(sc); - rxfilter = ath9k_hw_getrxfilter(ah); - ath9k_hw_setrxfilter(ah, rxfilter | - ATH9K_RX_FILTER_PHYRADAR | - ATH9K_RX_FILTER_PHYERR); - - /* TODO: usually this should not be neccesary, but for some reason - * (or in some mode?) the trigger must be called after the - * configuration, otherwise the register will have its values reset - * (on my ar9220 to value 0x01002310) - */ - ath9k_spectral_scan_config(hw, sc->spectral_mode); - ath9k_hw_ops(ah)->spectral_scan_trigger(ah); - ath9k_ps_restore(sc); -} - -int ath9k_spectral_scan_config(struct ieee80211_hw *hw, - enum spectral_mode spectral_mode) -{ - struct ath_softc *sc = hw->priv; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - - if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { - ath_err(common, "spectrum analyzer not implemented on this hardware\n"); - return -1; - } - - switch (spectral_mode) { - case SPECTRAL_DISABLED: - sc->spec_config.enabled = 0; - break; - case SPECTRAL_BACKGROUND: - /* send endless samples. - * TODO: is this really useful for "background"? - */ - sc->spec_config.endless = 1; - sc->spec_config.enabled = 1; - break; - case SPECTRAL_CHANSCAN: - case SPECTRAL_MANUAL: - sc->spec_config.endless = 0; - sc->spec_config.enabled = 1; - break; - default: - return -1; - } - - ath9k_ps_wakeup(sc); - ath9k_hw_ops(ah)->spectral_scan_config(ah, &sc->spec_config); - ath9k_ps_restore(sc); - - sc->spectral_mode = spectral_mode; - - return 0; -} - -static int ath9k_config(struct ieee80211_hw *hw, u32 changed) +static int ath9k_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &hw->conf; - bool reset_channel = false; + struct ath_chanctx *ctx = sc->cur_chan; ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); @@ -1161,7 +1506,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) * The chip needs a reset to properly wake up from * full sleep */ - reset_channel = ah->chip_fullsleep; + ath_chanctx_set_channel(sc, ctx, &ctx->chandef); } } @@ -1191,92 +1536,13 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } } - if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) { - struct ieee80211_channel *curchan = hw->conf.chandef.chan; - enum nl80211_channel_type channel_type = - cfg80211_get_chandef_type(&conf->chandef); - int pos = curchan->hw_value; - int old_pos = -1; - unsigned long flags; - - if (ah->curchan) - old_pos = ah->curchan - &ah->channels[0]; - - ath_dbg(common, CONFIG, "Set channel: %d MHz type: %d\n", - curchan->center_freq, channel_type); - - /* update survey stats for the old channel before switching */ - spin_lock_irqsave(&common->cc_lock, flags); - ath_update_survey_stats(sc); - spin_unlock_irqrestore(&common->cc_lock, flags); - - ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], - curchan, channel_type); - - /* - * If the operating channel changes, change the survey in-use flags - * along with it. - * Reset the survey data for the new channel, unless we're switching - * back to the operating channel from an off-channel operation. - */ - if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && - sc->cur_survey != &sc->survey[pos]) { - - if (sc->cur_survey) - sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; - - sc->cur_survey = &sc->survey[pos]; - - memset(sc->cur_survey, 0, sizeof(struct survey_info)); - sc->cur_survey->filled |= SURVEY_INFO_IN_USE; - } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { - memset(&sc->survey[pos], 0, sizeof(struct survey_info)); - } - - if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) { - ath_err(common, "Unable to set channel\n"); - mutex_unlock(&sc->mutex); - ath9k_ps_restore(sc); - return -EINVAL; - } - - /* - * The most recent snapshot of channel->noisefloor for the old - * channel is only available after the hardware reset. Copy it to - * the survey stats now. - */ - if (old_pos >= 0) - ath_update_survey_nf(sc, old_pos); - - /* - * Enable radar pulse detection if on a DFS channel. Spectral - * scanning and radar detection can not be used concurrently. - */ - if (hw->conf.radar_enabled) { - u32 rxfilter; - - /* set HW specific DFS configuration */ - ath9k_hw_set_radar_params(ah); - rxfilter = ath9k_hw_getrxfilter(ah); - rxfilter |= ATH9K_RX_FILTER_PHYRADAR | - ATH9K_RX_FILTER_PHYERR; - ath9k_hw_setrxfilter(ah, rxfilter); - ath_dbg(common, DFS, "DFS enabled at freq %d\n", - curchan->center_freq); - } else { - /* perform spectral scan if requested. */ - if (test_bit(SC_OP_SCANNING, &sc->sc_flags) && - sc->spectral_mode == SPECTRAL_CHANSCAN) - ath9k_spectral_scan_trigger(hw); - } + if (!ath9k_is_chanctx_enabled() && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { + ctx->offchannel = !!(conf->flags & IEEE80211_CONF_OFFCHANNEL); + ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef); } - if (changed & IEEE80211_CONF_CHANGE_POWER) { - ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level); - sc->config.txpowlimit = 2 * conf->power_level; - ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->config.txpowlimit, &sc->curtxpow); - } + if (changed & IEEE80211_CONF_CHANGE_POWER) + ath9k_set_txpower(sc, NULL); mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); @@ -1285,13 +1551,13 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) } #define SUPPORTED_FILTERS \ - (FIF_PROMISC_IN_BSS | \ - FIF_ALLMULTI | \ + (FIF_ALLMULTI | \ FIF_CONTROL | \ FIF_PSPOLL | \ FIF_OTHER_BSS | \ FIF_BCN_PRBRESP_PROMISC | \ FIF_PROBE_REQ | \ + FIF_MCAST_ACTION | \ FIF_FCSFAIL) /* FIXME: sc->sc_full_reset ? */ @@ -1301,12 +1567,19 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct ath_softc *sc = hw->priv; + struct ath_chanctx *ctx; u32 rfilt; - changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; - sc->rx.rxfilter = *total_flags; + spin_lock_bh(&sc->chan_lock); + ath_for_each_chanctx(sc, ctx) + ctx->rxfilter = *total_flags; +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + sc->offchannel.chan.rxfilter = *total_flags; +#endif + spin_unlock_bh(&sc->chan_lock); + ath9k_ps_wakeup(sc); rfilt = ath_calcrxfilter(sc); ath9k_hw_setrxfilter(sc->sc_ah, rfilt); @@ -1333,8 +1606,10 @@ static int ath9k_sta_add(struct ieee80211_hw *hw, return 0; key = ath_key_config(common, vif, sta, &ps_key); - if (key > 0) + if (key > 0) { an->ps_key = key; + an->key_idx[0] = key; + } return 0; } @@ -1345,13 +1620,13 @@ static void ath9k_del_ps_key(struct ath_softc *sc, { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_node *an = (struct ath_node *) sta->drv_priv; - struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key }; if (!an->ps_key) return; - ath_key_delete(common, &ps_key); + ath_key_delete(common, an->ps_key); an->ps_key = 0; + an->key_idx[0] = 0; } static int ath9k_sta_remove(struct ieee80211_hw *hw, @@ -1366,6 +1641,53 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw, return 0; } +static int ath9k_sta_state(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + int ret = 0; + + if (old_state == IEEE80211_STA_NOTEXIST && + new_state == IEEE80211_STA_NONE) { + ret = ath9k_sta_add(hw, vif, sta); + ath_dbg(common, CONFIG, + "Add station: %pM\n", sta->addr); + } else if (old_state == IEEE80211_STA_NONE && + new_state == IEEE80211_STA_NOTEXIST) { + ret = ath9k_sta_remove(hw, vif, sta); + ath_dbg(common, CONFIG, + "Remove station: %pM\n", sta->addr); + } + + if (ath9k_is_chanctx_enabled()) { + if (vif->type == NL80211_IFTYPE_STATION) { + if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTHORIZED) + ath_chanctx_event(sc, vif, + ATH_CHANCTX_EVENT_AUTHORIZED); + } + } + + return ret; +} + +static void ath9k_sta_set_tx_filter(struct ath_hw *ah, + struct ath_node *an, + bool set) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { + if (!an->key_idx[i]) + continue; + ath9k_hw_set_tx_filter(ah, an->key_idx[i], set); + } +} + static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd cmd, @@ -1374,15 +1696,14 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_node *an = (struct ath_node *) sta->drv_priv; - if (!sta->ht_cap.ht_supported) - return; - switch (cmd) { case STA_NOTIFY_SLEEP: an->sleeping = true; ath_tx_aggr_sleep(sta, sc, an); + ath9k_sta_set_tx_filter(sc->sc_ah, an, true); break; case STA_NOTIFY_AWAKE: + ath9k_sta_set_tx_filter(sc->sc_ah, an, false); an->sleeping = false; ath_tx_aggr_wakeup(sc, an); break; @@ -1390,7 +1711,8 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, } static int ath9k_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, u16 queue, + struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath_softc *sc = hw->priv; @@ -1438,7 +1760,8 @@ static int ath9k_set_key(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - int ret = 0; + struct ath_node *an = NULL; + int ret = 0, i; if (ath9k_modparam_nohwcrypt) return -ENOSPC; @@ -1458,15 +1781,33 @@ static int ath9k_set_key(struct ieee80211_hw *hw, return -EOPNOTSUPP; } + /* There may be MPDUs queued for the outgoing PTK key. Flush queues to + * make sure these are not send unencrypted or with a wrong (new) key + */ + if (cmd == DISABLE_KEY && key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + ieee80211_stop_queues(hw); + ath9k_flush(hw, vif, 0, true); + ieee80211_wake_queues(hw); + } + mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - ath_dbg(common, CONFIG, "Set HW Key\n"); + ath_dbg(common, CONFIG, "Set HW Key %d\n", cmd); + if (sta) + an = (struct ath_node *)sta->drv_priv; + + /* Delete pending key cache entries if no more frames are pointing to + * them in TXQs. + */ + for (i = 0; i < ATH_KEYMAX; i++) + ath9k_pending_key_del(sc, i); switch (cmd) { case SET_KEY: if (sta) ath9k_del_ps_key(sc, vif, sta); + key->hw_key_idx = 0; ret = ath_key_config(common, vif, sta, key); if (ret >= 0) { key->hw_key_idx = ret; @@ -1474,14 +1815,40 @@ static int ath9k_set_key(struct ieee80211_hw *hw, key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; if (key->cipher == WLAN_CIPHER_SUITE_TKIP) key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - if (sc->sc_ah->sw_mgmt_crypto && + if (sc->sc_ah->sw_mgmt_crypto_tx && key->cipher == WLAN_CIPHER_SUITE_CCMP) key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; ret = 0; } + if (an && key->hw_key_idx) { + for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { + if (an->key_idx[i]) + continue; + an->key_idx[i] = key->hw_key_idx; + break; + } + WARN_ON(i == ARRAY_SIZE(an->key_idx)); + } break; case DISABLE_KEY: - ath_key_delete(common, key); + if (ath9k_txq_has_key(sc, key->hw_key_idx)) { + /* Delay key cache entry deletion until there are no + * remaining TXQ frames pointing to this entry. + */ + set_bit(key->hw_key_idx, sc->sc_ah->pending_del_keymap); + ath_hw_keysetmac(common, key->hw_key_idx, NULL); + } else { + ath_key_delete(common, key->hw_key_idx); + } + if (an) { + for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) { + if (an->key_idx[i] != key->hw_key_idx) + continue; + an->key_idx[i] = 0; + break; + } + } + key->hw_key_idx = 0; break; default: ret = -EINVAL; @@ -1493,61 +1860,10 @@ static int ath9k_set_key(struct ieee80211_hw *hw, return ret; } -static void ath9k_set_assoc_state(struct ath_softc *sc, - struct ieee80211_vif *vif) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_vif *avp = (void *)vif->drv_priv; - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - unsigned long flags; - - set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); - avp->primary_sta_vif = true; - - /* - * Set the AID, BSSID and do beacon-sync only when - * the HW opmode is STATION. - * - * But the primary bit is set above in any case. - */ - if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) - return; - - memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - common->curaid = bss_conf->aid; - ath9k_hw_write_associd(sc->sc_ah); - - sc->last_rssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; - - spin_lock_irqsave(&sc->sc_pm_lock, flags); - sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; - spin_unlock_irqrestore(&sc->sc_pm_lock, flags); - - if (ath9k_hw_mci_is_enabled(sc->sc_ah)) - ath9k_mci_update_wlan_channels(sc, false); - - ath_dbg(common, CONFIG, - "Primary Station interface: %pM, BSSID: %pM\n", - vif->addr, common->curbssid); -} - -static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif) -{ - struct ath_softc *sc = data; - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - - if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) - return; - - if (bss_conf->assoc) - ath9k_set_assoc_state(sc, vif); -} - static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - u32 changed) + u64 changed) { #define CHECK_ANI \ (BSS_CHANGED_ASSOC | \ @@ -1565,50 +1881,35 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n", - bss_conf->bssid, bss_conf->assoc); - - if (avp->primary_sta_vif && !bss_conf->assoc) { - clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); - avp->primary_sta_vif = false; + bss_conf->bssid, vif->cfg.assoc); - if (ah->opmode == NL80211_IFTYPE_STATION) - clear_bit(SC_OP_BEACONS, &sc->sc_flags); - } - - ieee80211_iterate_active_interfaces_atomic( - sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - ath9k_bss_assoc_iter, sc); + memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); + avp->aid = vif->cfg.aid; + avp->assoc = vif->cfg.assoc; - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) && - ah->opmode == NL80211_IFTYPE_STATION) { - memset(common->curbssid, 0, ETH_ALEN); - common->curaid = 0; - ath9k_hw_write_associd(sc->sc_ah); - if (ath9k_hw_mci_is_enabled(sc->sc_ah)) - ath9k_mci_update_wlan_channels(sc, true); - } + ath9k_calculate_summary_state(sc, avp->chanctx); } - if (changed & BSS_CHANGED_IBSS) { + if ((changed & BSS_CHANGED_IBSS) || + (changed & BSS_CHANGED_OCB)) { memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - common->curaid = bss_conf->aid; + common->curaid = vif->cfg.aid; ath9k_hw_write_associd(sc->sc_ah); } if ((changed & BSS_CHANGED_BEACON_ENABLED) || - (changed & BSS_CHANGED_BEACON_INT)) { - if (ah->opmode == NL80211_IFTYPE_AP && - bss_conf->enable_beacon) - ath9k_set_tsfadjust(sc, vif); - if (ath9k_allow_beacon_config(sc, vif)) - ath9k_beacon_config(sc, vif, changed); + (changed & BSS_CHANGED_BEACON_INT) || + (changed & BSS_CHANGED_BEACON_INFO)) { + ath9k_calculate_summary_state(sc, avp->chanctx); } - if (changed & BSS_CHANGED_ERP_SLOT) { + if ((avp->chanctx == sc->cur_chan) && + (changed & BSS_CHANGED_ERP_SLOT)) { if (bss_conf->use_short_slot) slottime = 9; else slottime = 20; + if (vif->type == NL80211_IFTYPE_AP) { /* * Defer update, so that connected stations can adjust @@ -1623,9 +1924,18 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } } + if (changed & BSS_CHANGED_P2P_PS) + ath9k_p2p_bss_info_changed(sc, vif); + if (changed & CHECK_ANI) ath_check_ani(sc); + if (changed & BSS_CHANGED_TXPOWER) { + ath_dbg(common, CONFIG, "vif %pM power %d dbm power_type %d\n", + vif->addr, bss_conf->txpower, bss_conf->txpower_type); + ath9k_set_txpower(sc, vif); + } + mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); @@ -1635,11 +1945,19 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; + struct ath_vif *avp = (void *)vif->drv_priv; u64 tsf; mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - tsf = ath9k_hw_gettsf64(sc->sc_ah); + /* Get current TSF either from HW or kernel time. */ + if (sc->cur_chan == avp->chanctx) { + tsf = ath9k_hw_gettsf64(sc->sc_ah); + } else { + tsf = sc->cur_chan->tsf_val + + ath9k_hw_get_tsf_offset(sc->cur_chan->tsf_ts, 0); + } + tsf += le64_to_cpu(avp->tsf_adjust); ath9k_ps_restore(sc); mutex_unlock(&sc->mutex); @@ -1651,10 +1969,15 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) { struct ath_softc *sc = hw->priv; + struct ath_vif *avp = (void *)vif->drv_priv; mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - ath9k_hw_settsf64(sc->sc_ah, tsf); + tsf -= le64_to_cpu(avp->tsf_adjust); + avp->chanctx->tsf_ts = ktime_get_raw(); + if (sc->cur_chan == avp->chanctx) + ath9k_hw_settsf64(sc->sc_ah, tsf); + avp->chanctx->tsf_val = tsf; ath9k_ps_restore(sc); mutex_unlock(&sc->mutex); } @@ -1662,11 +1985,15 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; + struct ath_vif *avp = (void *)vif->drv_priv; mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - ath9k_hw_reset_tsf(sc->sc_ah); + avp->chanctx->tsf_ts = ktime_get_raw(); + if (sc->cur_chan == avp->chanctx) + ath9k_hw_reset_tsf(sc->sc_ah); + avp->chanctx->tsf_val = 0; ath9k_ps_restore(sc); mutex_unlock(&sc->mutex); @@ -1674,13 +2001,18 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) static int ath9k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, - u16 tid, u16 *ssn, u8 buf_size) + struct ieee80211_ampdu_params *params) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); bool flush = false; int ret = 0; + struct ieee80211_sta *sta = params->sta; + struct ath_node *an = (struct ath_node *)sta->drv_priv; + enum ieee80211_ampdu_mlme_action action = params->action; + u16 tid = params->tid; + u16 *ssn = ¶ms->ssn; + struct ath_atx_tid *atid; mutex_lock(&sc->mutex); @@ -1690,15 +2022,22 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_RX_STOP: break; case IEEE80211_AMPDU_TX_START: + if (ath9k_is_chanctx_enabled()) { + if (test_bit(ATH_OP_SCANNING, &common->op_flags)) { + ret = -EBUSY; + break; + } + } ath9k_ps_wakeup(sc); ret = ath_tx_aggr_start(sc, sta, tid, ssn); if (!ret) - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; ath9k_ps_restore(sc); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: flush = true; + fallthrough; case IEEE80211_AMPDU_TX_STOP_CONT: ath9k_ps_wakeup(sc); ath_tx_aggr_stop(sc, sta, tid); @@ -1707,9 +2046,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ath9k_ps_restore(sc); break; case IEEE80211_AMPDU_TX_OPERATIONAL: - ath9k_ps_wakeup(sc); - ath_tx_aggr_resume(sc, sta, tid); - ath9k_ps_restore(sc); + atid = ath_node_to_tid(an, tid); + atid->baw_size = IEEE80211_MIN_AMPDU_BUF << + sta->deflink.ht_cap.ampdu_factor; break; default: ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n"); @@ -1730,18 +2069,21 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, unsigned long flags; int pos; + if (IS_ENABLED(CONFIG_ATH9K_TX99)) + return -EOPNOTSUPP; + spin_lock_irqsave(&common->cc_lock, flags); if (idx == 0) ath_update_survey_stats(sc); - sband = hw->wiphy->bands[IEEE80211_BAND_2GHZ]; + sband = hw->wiphy->bands[NL80211_BAND_2GHZ]; if (sband && idx >= sband->n_channels) { idx -= sband->n_channels; sband = NULL; } if (!sband) - sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ]; + sband = hw->wiphy->bands[NL80211_BAND_5GHZ]; if (!sband || idx >= sband->n_channels) { spin_unlock_irqrestore(&common->cc_lock, flags); @@ -1757,64 +2099,132 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, return 0; } -static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) +static void ath9k_enable_dynack(struct ath_softc *sc) +{ +#ifdef CONFIG_ATH9K_DYNACK + u32 rfilt; + struct ath_hw *ah = sc->sc_ah; + + ath_dynack_reset(ah); + + ah->dynack.enabled = true; + rfilt = ath_calcrxfilter(sc); + ath9k_hw_setrxfilter(ah, rfilt); +#endif +} + +static void ath9k_set_coverage_class(struct ieee80211_hw *hw, + int radio_idx, + s16 coverage_class) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; + if (IS_ENABLED(CONFIG_ATH9K_TX99)) + return; + mutex_lock(&sc->mutex); - ah->coverage_class = coverage_class; - ath9k_ps_wakeup(sc); - ath9k_hw_init_global_settings(ah); - ath9k_ps_restore(sc); + if (coverage_class >= 0) { + ah->coverage_class = coverage_class; + if (ah->dynack.enabled) { + u32 rfilt; + + ah->dynack.enabled = false; + rfilt = ath_calcrxfilter(sc); + ath9k_hw_setrxfilter(ah, rfilt); + } + ath9k_ps_wakeup(sc); + ath9k_hw_init_global_settings(ah); + ath9k_ps_restore(sc); + } else if (!ah->dynack.enabled) { + ath9k_enable_dynack(sc); + } mutex_unlock(&sc->mutex); } -static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static bool ath9k_has_tx_pending(struct ath_softc *sc, + bool sw_pending) +{ + int i, npend = 0; + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (!ATH_TXQ_SETUP(sc, i)) + continue; + + npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i], + sw_pending); + if (npend) + break; + } + + return !!npend; +} + +static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + if (ath9k_is_chanctx_enabled()) { + if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) + goto flush; + + /* + * If MCC is active, extend the flush timeout + * and wait for the HW/SW queues to become + * empty. This needs to be done outside the + * sc->mutex lock to allow the channel scheduler + * to switch channel contexts. + * + * The vif queues have been stopped in mac80211, + * so there won't be any incoming frames. + */ + __ath9k_flush(hw, queues, drop, true, true); + return; + } +flush: + mutex_lock(&sc->mutex); + __ath9k_flush(hw, queues, drop, true, false); + mutex_unlock(&sc->mutex); +} + +void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop, + bool sw_pending, bool timeout_override) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - int timeout = 200; /* ms */ - int i, j; + int timeout; bool drain_txq; - mutex_lock(&sc->mutex); - cancel_delayed_work_sync(&sc->tx_complete_work); + cancel_delayed_work_sync(&sc->hw_check_work); if (ah->ah_flags & AH_UNPLUGGED) { ath_dbg(common, ANY, "Device has been unplugged!\n"); - mutex_unlock(&sc->mutex); return; } - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); - mutex_unlock(&sc->mutex); return; } - for (j = 0; j < timeout; j++) { - bool npend = false; - - if (j) - usleep_range(1000, 2000); - - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (!ATH_TXQ_SETUP(sc, i)) - continue; - - npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]); + spin_lock_bh(&sc->chan_lock); + if (timeout_override) + timeout = HZ / 5; + else + timeout = sc->cur_chan->flush_timeout; + spin_unlock_bh(&sc->chan_lock); - if (npend) - break; - } + ath_dbg(common, CHAN_CTX, + "Flush timeout: %d\n", jiffies_to_msecs(timeout)); - if (!npend) - break; - } + if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc, sw_pending), + timeout) > 0) + drop = false; if (drop) { ath9k_ps_wakeup(sc); @@ -1823,29 +2233,20 @@ static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) spin_unlock_bh(&sc->sc_pcu_lock); if (!drain_txq) - ath_reset(sc); + ath_reset(sc, NULL); ath9k_ps_restore(sc); - ieee80211_wake_queues(hw); } - ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); - mutex_unlock(&sc->mutex); + ieee80211_queue_delayed_work(hw, &sc->hw_check_work, + msecs_to_jiffies(ATH_HW_CHECK_POLL_INT)); } static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - int i; - - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (!ATH_TXQ_SETUP(sc, i)) - continue; - if (ath9k_has_pending_frames(sc, &sc->tx.txq[i])) - return true; - } - return false; + return ath9k_has_tx_pending(sc, true); } static int ath9k_tx_last_beacon(struct ieee80211_hw *hw) @@ -1938,7 +2339,8 @@ static bool validate_antenna_mask(struct ath_hw *ah, u32 val) } } -static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +static int ath9k_set_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 tx_ant, u32 rx_ant) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; @@ -1962,12 +2364,13 @@ static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant); ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant); - ath9k_reload_chainmask_settings(sc); + ath9k_cmn_reload_chainmask(ah); return 0; } -static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +static int ath9k_get_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 *tx_ant, u32 *rx_ant) { struct ath_softc *sc = hw->priv; @@ -1976,346 +2379,419 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) return 0; } -#ifdef CONFIG_PM_SLEEP - -static void ath9k_wow_map_triggers(struct ath_softc *sc, - struct cfg80211_wowlan *wowlan, - u32 *wow_triggers) +static void ath9k_sw_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *mac_addr) { - if (wowlan->disconnect) - *wow_triggers |= AH_WOW_LINK_CHANGE | - AH_WOW_BEACON_MISS; - if (wowlan->magic_pkt) - *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; - - if (wowlan->n_patterns) - *wow_triggers |= AH_WOW_USER_PATTERN_EN; + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct cfg80211_chan_def *chandef = &sc->cur_chan->chandef; + struct ieee80211_channel *chan = chandef->chan; + int pos = chan->hw_value; + set_bit(ATH_OP_SCANNING, &common->op_flags); + + /* Reset current survey */ + if (!sc->cur_chan->offchannel) { + if (sc->cur_survey != &sc->survey[pos]) { + if (sc->cur_survey) + sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; + sc->cur_survey = &sc->survey[pos]; + } - sc->wow_enabled = *wow_triggers; + memset(sc->cur_survey, 0, sizeof(struct survey_info)); + sc->cur_survey->filled |= SURVEY_INFO_IN_USE; + } +} +static void ath9k_sw_scan_complete(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + clear_bit(ATH_OP_SCANNING, &common->op_flags); } -static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + +static void ath9k_cancel_pending_offchannel(struct ath_softc *sc) { - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - int pattern_count = 0; - int i, byte_cnt; - u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; - u8 dis_deauth_mask[MAX_PATTERN_SIZE]; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); - memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE); - memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE); + if (sc->offchannel.roc_vif) { + ath_dbg(common, CHAN_CTX, + "%s: Aborting RoC\n", __func__); - /* - * Create Dissassociate / Deauthenticate packet filter - * - * 2 bytes 2 byte 6 bytes 6 bytes 6 bytes - * +--------------+----------+---------+--------+--------+---- - * + Frame Control+ Duration + DA + SA + BSSID + - * +--------------+----------+---------+--------+--------+---- - * - * The above is the management frame format for disassociate/ - * deauthenticate pattern, from this we need to match the first byte - * of 'Frame Control' and DA, SA, and BSSID fields - * (skipping 2nd byte of FC and Duration feild. - * - * Disassociate pattern - * -------------------- - * Frame control = 00 00 1010 - * DA, SA, BSSID = x:x:x:x:x:x - * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x - * | x:x:x:x:x:x -- 22 bytes - * - * Deauthenticate pattern - * ---------------------- - * Frame control = 00 00 1100 - * DA, SA, BSSID = x:x:x:x:x:x - * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x - * | x:x:x:x:x:x -- 22 bytes - */ + timer_delete_sync(&sc->offchannel.timer); + if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START) + ath_roc_complete(sc, ATH_ROC_COMPLETE_ABORT); + } - /* Create Disassociate Pattern first */ + if (test_bit(ATH_OP_SCANNING, &common->op_flags)) { + ath_dbg(common, CHAN_CTX, + "%s: Aborting HW scan\n", __func__); - byte_cnt = 0; + timer_delete_sync(&sc->offchannel.timer); + ath_scan_complete(sc, true); + } +} - /* Fill out the mask with all FF's */ +static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *hw_req) +{ + struct cfg80211_scan_request *req = &hw_req->req; + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + int ret = 0; - for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++) - dis_deauth_mask[i] = 0xff; + mutex_lock(&sc->mutex); - /* copy the first byte of frame control field */ - dis_deauth_pattern[byte_cnt] = 0xa0; - byte_cnt++; + if (WARN_ON(sc->offchannel.scan_req)) { + ret = -EBUSY; + goto out; + } - /* skip 2nd byte of frame control and Duration field */ - byte_cnt += 3; + ath9k_ps_wakeup(sc); + set_bit(ATH_OP_SCANNING, &common->op_flags); + sc->offchannel.scan_vif = vif; + sc->offchannel.scan_req = req; + sc->offchannel.scan_idx = 0; - /* - * need not match the destination mac address, it can be a broadcast - * mac address or an unicast to this station - */ - byte_cnt += 6; + ath_dbg(common, CHAN_CTX, "HW scan request received on vif: %pM\n", + vif->addr); - /* copy the source mac address */ - memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); + if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) { + ath_dbg(common, CHAN_CTX, "Starting HW scan\n"); + ath_offchannel_next(sc); + } - byte_cnt += 6; +out: + mutex_unlock(&sc->mutex); - /* copy the bssid, its same as the source mac address */ + return ret; +} - memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); +static void ath9k_cancel_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); - /* Create Disassociate pattern mask */ + ath_dbg(common, CHAN_CTX, "Cancel HW scan on vif: %pM\n", vif->addr); - dis_deauth_mask[0] = 0xfe; - dis_deauth_mask[1] = 0x03; - dis_deauth_mask[2] = 0xc0; + mutex_lock(&sc->mutex); + timer_delete_sync(&sc->offchannel.timer); + ath_scan_complete(sc, true); + mutex_unlock(&sc->mutex); +} - ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); +static int ath9k_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel *chan, int duration, + enum ieee80211_roc_type type) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + int ret = 0; - ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, - pattern_count, byte_cnt); + mutex_lock(&sc->mutex); - pattern_count++; - /* - * for de-authenticate pattern, only the first byte of the frame - * control field gets changed from 0xA0 to 0xC0 - */ - dis_deauth_pattern[0] = 0xC0; + if (WARN_ON(sc->offchannel.roc_vif)) { + ret = -EBUSY; + goto out; + } + + ath9k_ps_wakeup(sc); + sc->offchannel.roc_vif = vif; + sc->offchannel.roc_chan = chan; + sc->offchannel.roc_duration = duration; + + ath_dbg(common, CHAN_CTX, + "RoC request on vif: %pM, type: %d duration: %d\n", + vif->addr, type, duration); + + if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) { + ath_dbg(common, CHAN_CTX, "Starting RoC period\n"); + ath_offchannel_next(sc); + } - ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, - pattern_count, byte_cnt); +out: + mutex_unlock(&sc->mutex); + return ret; } -static void ath9k_wow_add_pattern(struct ath_softc *sc, - struct cfg80211_wowlan *wowlan) +static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { - struct ath_hw *ah = sc->sc_ah; - struct ath9k_wow_pattern *wow_pattern = NULL; - struct cfg80211_wowlan_trig_pkt_pattern *patterns = wowlan->patterns; - int mask_len; - s8 i = 0; + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); - if (!wowlan->n_patterns) - return; + mutex_lock(&sc->mutex); - /* - * Add the new user configured patterns - */ - for (i = 0; i < wowlan->n_patterns; i++) { + ath_dbg(common, CHAN_CTX, "Cancel RoC\n"); + timer_delete_sync(&sc->offchannel.timer); + + if (sc->offchannel.roc_vif) { + if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START) + ath_roc_complete(sc, ATH_ROC_COMPLETE_CANCEL); + } - wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL); + mutex_unlock(&sc->mutex); - if (!wow_pattern) - return; + return 0; +} - /* - * TODO: convert the generic user space pattern to - * appropriate chip specific/802.11 pattern. - */ +static int ath9k_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_chanctx *ctx, **ptr; + int pos; - mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); - memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE); - memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE); - memcpy(wow_pattern->pattern_bytes, patterns[i].pattern, - patterns[i].pattern_len); - memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len); - wow_pattern->pattern_len = patterns[i].pattern_len; + mutex_lock(&sc->mutex); - /* - * just need to take care of deauth and disssoc pattern, - * make sure we don't overwrite them. - */ + ath_for_each_chanctx(sc, ctx) { + if (ctx->assigned) + continue; + + ptr = (void *) conf->drv_priv; + *ptr = ctx; + ctx->assigned = true; + pos = ctx - &sc->chanctx[0]; + ctx->hw_queue_base = pos * IEEE80211_NUM_ACS; + + ath_dbg(common, CHAN_CTX, + "Add channel context: %d MHz\n", + conf->def.chan->center_freq); - ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes, - wow_pattern->mask_bytes, - i + 2, - wow_pattern->pattern_len); - kfree(wow_pattern); + ath_chanctx_set_channel(sc, ctx, &conf->def); + mutex_unlock(&sc->mutex); + return 0; } + mutex_unlock(&sc->mutex); + return -ENOSPC; } -static int ath9k_suspend(struct ieee80211_hw *hw, - struct cfg80211_wowlan *wowlan) + +static void ath9k_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf) { struct ath_softc *sc = hw->priv; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u32 wow_triggers_enabled = 0; - int ret = 0; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_chanctx *ctx = ath_chanctx_get(conf); mutex_lock(&sc->mutex); - ath_cancel_work(sc); - ath_stop_ani(sc); - del_timer_sync(&sc->rx_poll_timer); - - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { - ath_dbg(common, ANY, "Device not present\n"); - ret = -EINVAL; - goto fail_wow; - } + ath_dbg(common, CHAN_CTX, + "Remove channel context: %d MHz\n", + conf->def.chan->center_freq); - if (WARN_ON(!wowlan)) { - ath_dbg(common, WOW, "None of the WoW triggers enabled\n"); - ret = -EINVAL; - goto fail_wow; - } + ctx->assigned = false; + ctx->hw_queue_base = 0; + ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN); - if (!device_can_wakeup(sc->dev)) { - ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n"); - ret = 1; - goto fail_wow; - } + mutex_unlock(&sc->mutex); +} - /* - * none of the sta vifs are associated - * and we are not currently handling multivif - * cases, for instance we have to seperately - * configure 'keep alive frame' for each - * STA. - */ +static void ath9k_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf, + u32 changed) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_chanctx *ctx = ath_chanctx_get(conf); - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { - ath_dbg(common, WOW, "None of the STA vifs are associated\n"); - ret = 1; - goto fail_wow; - } + mutex_lock(&sc->mutex); + ath_dbg(common, CHAN_CTX, + "Change channel context: %d MHz\n", + conf->def.chan->center_freq); + ath_chanctx_set_channel(sc, ctx, &conf->def); + mutex_unlock(&sc->mutex); +} - if (sc->nvifs > 1) { - ath_dbg(common, WOW, "WoW for multivif is not yet supported\n"); - ret = 1; - goto fail_wow; - } +static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *conf) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_vif *avp = (void *)vif->drv_priv; + struct ath_chanctx *ctx = ath_chanctx_get(conf); + int i; - ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled); + ath9k_cancel_pending_offchannel(sc); - ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n", - wow_triggers_enabled); + mutex_lock(&sc->mutex); - ath9k_ps_wakeup(sc); + ath_dbg(common, CHAN_CTX, + "Assign VIF (addr: %pM, type: %d, p2p: %d) to channel context: %d MHz\n", + vif->addr, vif->type, vif->p2p, + conf->def.chan->center_freq); - ath9k_stop_btcoex(sc); + avp->chanctx = ctx; + ctx->nvifs_assigned++; + list_add_tail(&avp->list, &ctx->vifs); + ath9k_calculate_summary_state(sc, ctx); + for (i = 0; i < IEEE80211_NUM_ACS; i++) + vif->hw_queue[i] = ctx->hw_queue_base + i; - /* - * Enable wake up on recieving disassoc/deauth - * frame by default. - */ - ath9k_wow_add_disassoc_deauth_pattern(sc); + mutex_unlock(&sc->mutex); - if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN) - ath9k_wow_add_pattern(sc, wowlan); + return 0; +} - spin_lock_bh(&sc->sc_pcu_lock); - /* - * To avoid false wake, we enable beacon miss interrupt only - * when we go to sleep. We save the current interrupt mask - * so we can restore it after the system wakes up - */ - sc->wow_intr_before_sleep = ah->imask; - ah->imask &= ~ATH9K_INT_GLOBAL; - ath9k_hw_disable_interrupts(ah); - ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL; - ath9k_hw_set_interrupts(ah); - ath9k_hw_enable_interrupts(ah); +static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *conf) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_vif *avp = (void *)vif->drv_priv; + struct ath_chanctx *ctx = ath_chanctx_get(conf); + int ac; - spin_unlock_bh(&sc->sc_pcu_lock); + ath9k_cancel_pending_offchannel(sc); - /* - * we can now sync irq and kill any running tasklets, since we already - * disabled interrupts and not holding a spin lock - */ - synchronize_irq(sc->irq); - tasklet_kill(&sc->intr_tq); + mutex_lock(&sc->mutex); - ath9k_hw_wow_enable(ah, wow_triggers_enabled); + ath_dbg(common, CHAN_CTX, + "Remove VIF (addr: %pM, type: %d, p2p: %d) from channel context: %d MHz\n", + vif->addr, vif->type, vif->p2p, + conf->def.chan->center_freq); - ath9k_ps_restore(sc); - ath_dbg(common, ANY, "WoW enabled in ath9k\n"); - atomic_inc(&sc->wow_sleep_proc_intr); + avp->chanctx = NULL; + ctx->nvifs_assigned--; + list_del(&avp->list); + ath9k_calculate_summary_state(sc, ctx); + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) + vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE; -fail_wow: mutex_unlock(&sc->mutex); - return ret; } -static int ath9k_resume(struct ieee80211_hw *hw) +static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_prep_tx_info *info) { struct ath_softc *sc = hw->priv; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u32 wow_status; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_vif *avp = (struct ath_vif *) vif->drv_priv; + struct ath_beacon_config *cur_conf; + struct ath_chanctx *go_ctx; + unsigned long timeout; + bool changed = false; + u32 beacon_int; + + if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) + return; - mutex_lock(&sc->mutex); + if (!avp->chanctx) + return; - ath9k_ps_wakeup(sc); + mutex_lock(&sc->mutex); - spin_lock_bh(&sc->sc_pcu_lock); + spin_lock_bh(&sc->chan_lock); + if (sc->next_chan || (sc->cur_chan != avp->chanctx)) + changed = true; + spin_unlock_bh(&sc->chan_lock); - ath9k_hw_disable_interrupts(ah); - ah->imask = sc->wow_intr_before_sleep; - ath9k_hw_set_interrupts(ah); - ath9k_hw_enable_interrupts(ah); + if (!changed) + goto out; - spin_unlock_bh(&sc->sc_pcu_lock); + ath9k_cancel_pending_offchannel(sc); - wow_status = ath9k_hw_wow_wakeup(ah); + go_ctx = ath_is_go_chanctx_present(sc); - if (atomic_read(&sc->wow_got_bmiss_intr) == 0) { + if (go_ctx) { /* - * some devices may not pick beacon miss - * as the reason they woke up so we add - * that here for that shortcoming. + * Wait till the GO interface gets a chance + * to send out an NoA. */ - wow_status |= AH_WOW_BEACON_MISS; - atomic_dec(&sc->wow_got_bmiss_intr); - ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n"); - } + spin_lock_bh(&sc->chan_lock); + sc->sched.mgd_prepare_tx = true; + cur_conf = &go_ctx->beacon; + beacon_int = TU_TO_USEC(cur_conf->beacon_interval); + spin_unlock_bh(&sc->chan_lock); + + timeout = usecs_to_jiffies(beacon_int * 2); + init_completion(&sc->go_beacon); + + mutex_unlock(&sc->mutex); + + if (wait_for_completion_timeout(&sc->go_beacon, + timeout) == 0) { + ath_dbg(common, CHAN_CTX, + "Failed to send new NoA\n"); - atomic_dec(&sc->wow_sleep_proc_intr); + spin_lock_bh(&sc->chan_lock); + sc->sched.mgd_prepare_tx = false; + spin_unlock_bh(&sc->chan_lock); + } - if (wow_status) { - ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n", - ath9k_hw_wow_event_to_string(wow_status), wow_status); + mutex_lock(&sc->mutex); } - ath_restart_work(sc); - ath9k_start_btcoex(sc); + ath_dbg(common, CHAN_CTX, + "%s: Set chanctx state to FORCE_ACTIVE for vif: %pM\n", + __func__, vif->addr); - ath9k_ps_restore(sc); - mutex_unlock(&sc->mutex); + spin_lock_bh(&sc->chan_lock); + sc->next_chan = avp->chanctx; + sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE; + spin_unlock_bh(&sc->chan_lock); - return 0; + ath_chanctx_set_next(sc, true); +out: + mutex_unlock(&sc->mutex); } -static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) +void ath9k_fill_chanctx_ops(void) { - struct ath_softc *sc = hw->priv; + if (!ath9k_is_chanctx_enabled()) + return; - mutex_lock(&sc->mutex); - device_init_wakeup(sc->dev, 1); - device_set_wakeup_enable(sc->dev, enabled); - mutex_unlock(&sc->mutex); + ath9k_ops.hw_scan = ath9k_hw_scan; + ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan; + ath9k_ops.remain_on_channel = ath9k_remain_on_channel; + ath9k_ops.cancel_remain_on_channel = ath9k_cancel_remain_on_channel; + ath9k_ops.add_chanctx = ath9k_add_chanctx; + ath9k_ops.remove_chanctx = ath9k_remove_chanctx; + ath9k_ops.change_chanctx = ath9k_change_chanctx; + ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx; + ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx; + ath9k_ops.mgd_prepare_tx = ath9k_mgd_prepare_tx; } #endif -static void ath9k_sw_scan_start(struct ieee80211_hw *hw) -{ - struct ath_softc *sc = hw->priv; - set_bit(SC_OP_SCANNING, &sc->sc_flags); -} -static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) +static int ath9k_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, int *dbm) { struct ath_softc *sc = hw->priv; - clear_bit(SC_OP_SCANNING, &sc->sc_flags); + struct ath_vif *avp = (void *)vif->drv_priv; + + mutex_lock(&sc->mutex); + if (avp->chanctx) + *dbm = avp->chanctx->cur_txpower; + else + *dbm = sc->cur_chan->cur_txpower; + mutex_unlock(&sc->mutex); + + *dbm /= 2; + + return 0; } struct ieee80211_ops ath9k_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = ath9k_tx, .start = ath9k_start, .stop = ath9k_stop, @@ -2324,8 +2800,7 @@ struct ieee80211_ops ath9k_ops = { .remove_interface = ath9k_remove_interface, .config = ath9k_config, .configure_filter = ath9k_configure_filter, - .sta_add = ath9k_sta_add, - .sta_remove = ath9k_sta_remove, + .sta_state = ath9k_sta_state, .sta_notify = ath9k_sta_notify, .conf_tx = ath9k_conf_tx, .bss_info_changed = ath9k_bss_info_changed, @@ -2345,7 +2820,7 @@ struct ieee80211_ops ath9k_ops = { .set_antenna = ath9k_set_antenna, .get_antenna = ath9k_get_antenna, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_ATH9K_WOW .suspend = ath9k_suspend, .resume = ath9k_resume, .set_wakeup = ath9k_set_wakeup, @@ -2357,10 +2832,11 @@ struct ieee80211_ops ath9k_ops = { .get_et_strings = ath9k_get_et_strings, #endif -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) +#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_STATION_STATISTICS) .sta_add_debugfs = ath9k_sta_add_debugfs, - .sta_remove_debugfs = ath9k_sta_remove_debugfs, #endif .sw_scan_start = ath9k_sw_scan_start, .sw_scan_complete = ath9k_sw_scan_complete, + .get_txpower = ath9k_get_txpower, + .wake_tx_queue = ath9k_wake_tx_queue, }; diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 815bee21c19a..a0845002d6fe 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -43,7 +43,7 @@ static bool ath_mci_add_profile(struct ath_common *common, struct ath_mci_profile_info *info) { struct ath_mci_profile_info *entry; - u8 voice_priority[] = { 110, 110, 110, 112, 110, 110, 114, 116, 118 }; + static const u8 voice_priority[] = { 110, 110, 110, 112, 110, 110, 114, 116, 118 }; if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) && (info->type == MCI_GPM_COEX_PROFILE_VOICE)) @@ -200,7 +200,7 @@ skip_tuning: if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE) btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE; - btcoex->btcoex_no_stomp = btcoex->btcoex_period * 1000 * + btcoex->btcoex_no_stomp = btcoex->btcoex_period * (100 - btcoex->duty_cycle) / 100; ath9k_hw_btcoex_enable(sc->sc_ah); @@ -266,7 +266,9 @@ static void ath_mci_set_concur_txprio(struct ath_softc *sc) stomp_txprio[ATH_BTCOEX_STOMP_NONE] = ATH_MCI_INQUIRY_PRIO; } else { - u8 prof_prio[] = { 50, 90, 94, 52 };/* RFCOMM, A2DP, HID, PAN */ + static const u8 prof_prio[] = { + 50, 90, 94, 52 + }; /* RFCOMM, A2DP, HID, PAN */ stomp_txprio[ATH_BTCOEX_STOMP_LOW] = stomp_txprio[ATH_BTCOEX_STOMP_NONE] = 0xff; @@ -453,7 +455,7 @@ int ath_mci_setup(struct ath_softc *sc) mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE; mci->gpm_buf.bf_len = ATH_MCI_GPM_BUF_SIZE; - mci->gpm_buf.bf_addr = (u8 *)mci->sched_buf.bf_addr + mci->sched_buf.bf_len; + mci->gpm_buf.bf_addr = mci->sched_buf.bf_addr + mci->sched_buf.bf_len; mci->gpm_buf.bf_paddr = mci->sched_buf.bf_paddr + mci->sched_buf.bf_len; ret = ar9003_mci_setup(sc->sc_ah, mci->gpm_buf.bf_paddr, @@ -495,7 +497,7 @@ void ath_mci_intr(struct ath_softc *sc) ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg); if (ar9003_mci_state(ah, MCI_STATE_ENABLE) == 0) { - ar9003_mci_get_next_gpm_offset(ah, true, NULL); + ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET); return; } @@ -548,19 +550,18 @@ void ath_mci_intr(struct ath_softc *sc) if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO; - offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET); + ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET); } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM; while (more_data == MCI_GPM_MORE) { - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) return; pgpm = mci->gpm_buf.bf_addr; - offset = ar9003_mci_get_next_gpm_offset(ah, false, - &more_data); + offset = ar9003_mci_get_next_gpm_offset(ah, &more_data); if (offset == MCI_GPM_INVALID) break; @@ -661,9 +662,9 @@ void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all) chan_start = wlan_chan - 10; chan_end = wlan_chan + 10; - if (chan->chanmode == CHANNEL_G_HT40PLUS) + if (IS_CHAN_HT40PLUS(chan)) chan_end += 20; - else if (chan->chanmode == CHANNEL_G_HT40MINUS) + else if (IS_CHAN_HT40MINUS(chan)) chan_start -= 20; /* adjust side band */ @@ -706,12 +707,12 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel, return; if (setchannel) { - struct ath9k_hw_cal_data *caldata = &sc->caldata; - if ((caldata->chanmode == CHANNEL_G_HT40PLUS) && + struct ath9k_hw_cal_data *caldata = &sc->cur_chan->caldata; + if (IS_CHAN_HT40PLUS(ah->curchan) && (ah->curchan->channel > caldata->channel) && (ah->curchan->channel <= caldata->channel + 20)) return; - if ((caldata->chanmode == CHANNEL_G_HT40MINUS) && + if (IS_CHAN_HT40MINUS(ah->curchan) && (ah->curchan->channel < caldata->channel) && (ah->curchan->channel >= caldata->channel - 20)) return; @@ -720,7 +721,7 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel, mci_hw->concur_tx = concur_tx; if (old_concur_tx != mci_hw->concur_tx) - ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); + ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); } static void ath9k_mci_stomp_audio(struct ath_softc *sc) diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index c585c9b35973..27d4034c814e 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -18,55 +18,302 @@ #include <linux/nl80211.h> #include <linux/pci.h> -#include <linux/pci-aspm.h> -#include <linux/ath9k_platform.h> #include <linux/module.h> #include "ath9k.h" -static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { +static const struct pci_device_id ath_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ + +#ifdef CONFIG_ATH9K_PCOEM + /* Mini PCI AR9220 MB92 cards: Compex WLM200NX, Wistron DNMA-92 */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0029, + PCI_VENDOR_ID_ATHEROS, + 0x2096), + .driver_data = ATH9K_PCI_LED_ACT_HI }, +#endif + { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ + +#ifdef CONFIG_ATH9K_PCOEM + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + PCI_VENDOR_ID_AZWAVE, + 0x1C71), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + PCI_VENDOR_ID_FOXCONN, + 0xE01F), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x11AD, /* LITEON */ + 0x6632), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x11AD, /* LITEON */ + 0x6642), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + PCI_VENDOR_ID_QMI, + 0x0306), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x185F, /* WNC */ + 0x309D), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x10CF, /* Fujitsu */ + 0x147C), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x10CF, /* Fujitsu */ + 0x147D), + .driver_data = ATH9K_PCI_D3_L1_WAR }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002A, + 0x10CF, /* Fujitsu */ + 0x1536), + .driver_data = ATH9K_PCI_D3_L1_WAR }, +#endif + { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ + +#ifdef CONFIG_ATH9K_PCOEM + /* AR9285 card for Asus */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x002B, + PCI_VENDOR_ID_AZWAVE, + 0x2C37), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, +#endif + { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */ { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ + + /* Killer Wireless (3x3) */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0030, + 0x1A56, + 0x2000), + .driver_data = ATH9K_PCI_KILLER }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0030, + 0x1A56, + 0x2001), + .driver_data = ATH9K_PCI_KILLER }, + { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */ +#ifdef CONFIG_ATH9K_PCOEM /* PCI-E CUS198 */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0032, PCI_VENDOR_ID_AZWAVE, 0x2086), - .driver_data = ATH9K_PCI_CUS198 }, + .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0032, PCI_VENDOR_ID_AZWAVE, 0x1237), - .driver_data = ATH9K_PCI_CUS198 }, + .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0032, PCI_VENDOR_ID_AZWAVE, 0x2126), - .driver_data = ATH9K_PCI_CUS198 }, + .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x126A), + .driver_data = ATH9K_PCI_CUS198 | ATH9K_PCI_BT_ANT_DIV }, /* PCI-E CUS230 */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0032, PCI_VENDOR_ID_AZWAVE, 0x2152), - .driver_data = ATH9K_PCI_CUS230 }, + .driver_data = ATH9K_PCI_CUS230 | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0032, PCI_VENDOR_ID_FOXCONN, 0xE075), - .driver_data = ATH9K_PCI_CUS230 }, + .driver_data = ATH9K_PCI_CUS230 | ATH9K_PCI_BT_ANT_DIV }, + + /* WB225 */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_ATHEROS, + 0x3119), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_ATHEROS, + 0x3122), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x185F, /* WNC */ + 0x3119), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x185F, /* WNC */ + 0x3027), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x4105), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x4106), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x410D), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x410E), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0x410F), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0xC706), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0xC680), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_SAMSUNG, + 0xC708), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_LENOVO, + 0x3218), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_LENOVO, + 0x3219), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, + + /* AR9485 cards with PLL power-save disabled by default. */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x2C97), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x2100), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x1C56, /* ASKEY */ + 0x4001), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x11AD, /* LITEON */ + 0x6627), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x11AD, /* LITEON */ + 0x6628), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_FOXCONN, + 0xE04E), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_FOXCONN, + 0xE04F), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x144F, /* ASKEY */ + 0x7197), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x1B9A, /* XAVI */ + 0x2000), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x1B9A, /* XAVI */ + 0x2001), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x1186), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x1F86), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x1195), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_AZWAVE, + 0x1F95), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x1B9A, /* XAVI */ + 0x1C00), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + 0x1B9A, /* XAVI */ + 0x1C01), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0032, + PCI_VENDOR_ID_ASUSTEK, + 0x850D), + .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +#endif { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E AR9485 */ { PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E AR9580 */ +#ifdef CONFIG_ATH9K_PCOEM /* PCI-E CUS217 */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0034, @@ -135,10 +382,396 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { 0x10CF, /* Fujitsu */ 0x1783), .driver_data = ATH9K_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + PCI_VENDOR_ID_DELL, + 0x020B), + .driver_data = ATH9K_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + PCI_VENDOR_ID_DELL, + 0x0300), + .driver_data = ATH9K_PCI_WOW }, + + /* Killer Wireless (2x2) */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0030, + 0x1A56, + 0x2003), + .driver_data = ATH9K_PCI_KILLER }, { PCI_VDEVICE(ATHEROS, 0x0034) }, /* PCI-E AR9462 */ { PCI_VDEVICE(ATHEROS, 0x0037) }, /* PCI-E AR1111/AR9485 */ - { PCI_VDEVICE(ATHEROS, 0x0036) }, /* PCI-E AR9565 */ + + /* CUS252 */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ATHEROS, + 0x3028), + .driver_data = ATH9K_PCI_CUS252 | + ATH9K_PCI_AR9565_2ANT | + ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x2176), + .driver_data = ATH9K_PCI_CUS252 | + ATH9K_PCI_AR9565_2ANT | + ATH9K_PCI_BT_ANT_DIV }, + + /* WB335 1-ANT */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE068), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x185F, /* WNC */ + 0xA119), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0632), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x06B2), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0842), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x1842), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x6671), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x2811), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x2812), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x28A1), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x28A3), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x218A), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x2F8A), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + + /* WB335 1-ANT / Antenna Diversity */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ATHEROS, + 0x3025), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ATHEROS, + 0x3026), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ATHEROS, + 0x302B), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE069), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x185F, /* WNC */ + 0x3028), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0622), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0672), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0662), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x06A2), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0682), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x213A), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x213C), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_HP, + 0x18E3), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_HP, + 0x217F), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_HP, + 0x2005), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_DELL, + 0x020C), + .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, + + /* WB335 2-ANT / Antenna-Diversity */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x411A), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x411B), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x411C), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x411D), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x411E), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x4129), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_SAMSUNG, + 0x412A), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ATHEROS, + 0x3027), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ATHEROS, + 0x302C), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0642), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0652), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0612), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0832), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x1832), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0692), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0803), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0813), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x2130), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x213B), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x2182), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x218B), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x218C), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x2F82), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x144F, /* ASKEY */ + 0x7202), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x2810), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x2813), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x28A2), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x28A4), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x185F, /* WNC */ + 0x3027), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x185F, /* WNC */ + 0xA120), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE07F), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE08F), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE081), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE091), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE099), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_LENOVO, + 0x3026), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_LENOVO, + 0x4026), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ASUSTEK, + 0x85F2), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_DELL, + 0x020E), + .driver_data = ATH9K_PCI_AR9565_2ANT | + ATH9K_PCI_BT_ANT_DIV | + ATH9K_PCI_LED_ACT_HI}, + + /* PCI-E AR9565 (WB335) */ + { PCI_VDEVICE(ATHEROS, 0x0036), + .driver_data = ATH9K_PCI_BT_ANT_DIV }, +#endif + { 0 } }; @@ -146,7 +779,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { /* return bus cachesize in 4B word units */ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) { - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; u8 u8tmp; pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, &u8tmp); @@ -164,46 +797,33 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) { - struct ath_softc *sc = (struct ath_softc *) common->priv; - struct ath9k_platform_data *pdata = sc->dev->platform_data; - - if (pdata) { - if (off >= (ARRAY_SIZE(pdata->eeprom_data))) { - ath_err(common, - "%s: eeprom read failed, offset %08x is out of range\n", - __func__, off); - } - - *data = pdata->eeprom_data[off]; - } else { - struct ath_hw *ah = (struct ath_hw *) common->ah; - - common->ops->read(ah, AR5416_EEPROM_OFFSET + - (off << AR5416_EEPROM_S)); + struct ath_hw *ah = common->ah; - if (!ath9k_hw_wait(ah, - AR_EEPROM_STATUS_DATA, - AR_EEPROM_STATUS_DATA_BUSY | - AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, - AH_WAIT_TIMEOUT)) { - return false; - } + common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); - *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA), - AR_EEPROM_STATUS_DATA_VAL); + if (!ath9k_hw_wait(ah, + AR_EEPROM_STATUS_DATA(ah), + AR_EEPROM_STATUS_DATA_BUSY | + AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, + AH_WAIT_TIMEOUT)) { + return false; } + *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA(ah)), + AR_EEPROM_STATUS_DATA_VAL); + return true; } /* Need to be called after we discover btcoex capabilities */ static void ath_pci_aspm_init(struct ath_common *common) { - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; struct ath_hw *ah = sc->sc_ah; struct pci_dev *pdev = to_pci_dev(sc->dev); struct pci_dev *parent; u16 aspm; + int ret; if (!ah->is_pciexpress) return; @@ -229,8 +849,24 @@ static void ath_pci_aspm_init(struct ath_common *common) return; } - pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &aspm); - if (aspm & (PCI_EXP_LNKCTL_ASPM_L0S | PCI_EXP_LNKCTL_ASPM_L1)) { + /* + * 0x70c - Ack Frequency Register. + * + * Bits 27:29 - DEFAULT_L1_ENTRANCE_LATENCY. + * + * 000 : 1 us + * 001 : 2 us + * 010 : 4 us + * 011 : 8 us + * 100 : 16 us + * 101 : 32 us + * 110/111 : 64 us + */ + if (AR_SREV_9462(ah)) + pci_read_config_dword(pdev, 0x70c, &ah->config.aspm_l1_fix); + + ret = pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &aspm); + if (!ret && (aspm & (PCI_EXP_LNKCTL_ASPM_L0S | PCI_EXP_LNKCTL_ASPM_L1))) { ah->aspm_enabled = true; /* Initialize PCIe PM and SERDES registers. */ ath9k_hw_configpcipowersave(ah, false); @@ -253,22 +889,17 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) u32 val; int ret = 0; char hw_name[64]; + int msi_enabled = 0; if (pcim_enable_device(pdev)) return -EIO; - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (ret) { pr_err("32-bit DMA not available\n"); return ret; } - ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) { - pr_err("32-bit DMA consistent DMA enable failed\n"); - return ret; - } - /* * Cache line size is used to size and align various * structures used to communicate with the hardware. @@ -308,6 +939,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENODEV; } + ath9k_fill_chanctx_ops(); hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); if (!hw) { dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); @@ -323,10 +955,20 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->mem = pcim_iomap_table(pdev)[0]; sc->driver_data = id->driver_data; - /* Will be cleared in ath9k_start() */ - set_bit(SC_OP_INVALID, &sc->sc_flags); + if (ath9k_use_msi) { + if (pci_enable_msi(pdev) == 0) { + msi_enabled = 1; + dev_err(&pdev->dev, "Using MSI\n"); + } else { + dev_err(&pdev->dev, "Using INTx\n"); + } + } + + if (!msi_enabled) + ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); + else + ret = request_irq(pdev->irq, ath_isr, 0, "ath9k", sc); - ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); goto err_irq; @@ -340,9 +982,12 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_init; } + sc->sc_ah->msi_enabled = msi_enabled; + sc->sc_ah->msi_reg = 0; + ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name)); - wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n", - hw_name, (unsigned long)sc->mem, pdev->irq); + wiphy_info(hw->wiphy, "%s mem=0x%p, irq=%d\n", + hw_name, sc->mem, pdev->irq); return 0; @@ -369,12 +1014,14 @@ static void ath_pci_remove(struct pci_dev *pdev) static int ath_pci_suspend(struct device *device) { - struct pci_dev *pdev = to_pci_dev(device); - struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = dev_get_drvdata(device); struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); - if (sc->wow_enabled) + if (test_bit(ATH_OP_WOW_ENABLED, &common->op_flags)) { + dev_info(device, "WOW is enabled, bypassing PCI suspend\n"); return 0; + } /* The device has to be moved to FULLSLEEP forcibly. * Otherwise the chip never moved to full sleep, @@ -382,6 +1029,7 @@ static int ath_pci_suspend(struct device *device) */ ath9k_stop_btcoex(sc); ath9k_hw_disable(sc->sc_ah); + timer_delete_sync(&sc->sleep_timer); ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); return 0; diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 8b380305b0fc..4a1b99238ec2 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -48,4 +48,11 @@ #define AR_PHY_PLL_CONTROL 0x16180 #define AR_PHY_PLL_MODE 0x16184 +enum ath9k_ant_div_comb_lna_conf { + ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2, + ATH_ANT_DIV_COMB_LNA2, + ATH_ANT_DIV_COMB_LNA1, + ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2, +}; + #endif diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c deleted file mode 100644 index 7eb1f4b458e4..000000000000 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ /dev/null @@ -1,1488 +0,0 @@ -/* - * Copyright (c) 2004 Video54 Technologies, Inc. - * Copyright (c) 2004-2011 Atheros Communications, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/slab.h> -#include <linux/export.h> - -#include "ath9k.h" - -static const struct ath_rate_table ar5416_11na_ratetable = { - 68, - 8, /* MCS start */ - { - [0] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, - 5400, 0, 12 }, /* 6 Mb */ - [1] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, - 7800, 1, 18 }, /* 9 Mb */ - [2] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, - 10000, 2, 24 }, /* 12 Mb */ - [3] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, - 13900, 3, 36 }, /* 18 Mb */ - [4] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, - 17300, 4, 48 }, /* 24 Mb */ - [5] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, - 23000, 5, 72 }, /* 36 Mb */ - [6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, - 27400, 6, 96 }, /* 48 Mb */ - [7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, - 29300, 7, 108 }, /* 54 Mb */ - [8] = { RC_HT_SDT_2040, WLAN_RC_PHY_HT_20_SS, 6500, - 6400, 0, 0 }, /* 6.5 Mb */ - [9] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000, - 12700, 1, 1 }, /* 13 Mb */ - [10] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500, - 18800, 2, 2 }, /* 19.5 Mb */ - [11] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000, - 25000, 3, 3 }, /* 26 Mb */ - [12] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000, - 36700, 4, 4 }, /* 39 Mb */ - [13] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000, - 48100, 5, 5 }, /* 52 Mb */ - [14] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500, - 53500, 6, 6 }, /* 58.5 Mb */ - [15] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000, - 59000, 7, 7 }, /* 65 Mb */ - [16] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200, - 65400, 7, 7 }, /* 75 Mb */ - [17] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000, - 12700, 8, 8 }, /* 13 Mb */ - [18] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000, - 24800, 9, 9 }, /* 26 Mb */ - [19] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000, - 36600, 10, 10 }, /* 39 Mb */ - [20] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000, - 48100, 11, 11 }, /* 52 Mb */ - [21] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000, - 69500, 12, 12 }, /* 78 Mb */ - [22] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000, - 89500, 13, 13 }, /* 104 Mb */ - [23] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000, - 98900, 14, 14 }, /* 117 Mb */ - [24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000, - 108300, 15, 15 }, /* 130 Mb */ - [25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400, - 120000, 15, 15 }, /* 144.4 Mb */ - [26] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500, - 17400, 16, 16 }, /* 19.5 Mb */ - [27] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000, - 35100, 17, 17 }, /* 39 Mb */ - [28] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500, - 52600, 18, 18 }, /* 58.5 Mb */ - [29] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000, - 70400, 19, 19 }, /* 78 Mb */ - [30] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000, - 104900, 20, 20 }, /* 117 Mb */ - [31] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000, - 115800, 20, 20 }, /* 130 Mb*/ - [32] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000, - 137200, 21, 21 }, /* 156 Mb */ - [33] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300, - 151100, 21, 21 }, /* 173.3 Mb */ - [34] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500, - 152800, 22, 22 }, /* 175.5 Mb */ - [35] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000, - 168400, 22, 22 }, /* 195 Mb*/ - [36] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000, - 168400, 23, 23 }, /* 195 Mb */ - [37] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700, - 185000, 23, 23 }, /* 216.7 Mb */ - [38] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500, - 13200, 0, 0 }, /* 13.5 Mb*/ - [39] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500, - 25900, 1, 1 }, /* 27.0 Mb*/ - [40] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500, - 38600, 2, 2 }, /* 40.5 Mb*/ - [41] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000, - 49800, 3, 3 }, /* 54 Mb */ - [42] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500, - 72200, 4, 4 }, /* 81 Mb */ - [43] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 108000, - 92900, 5, 5 }, /* 108 Mb */ - [44] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500, - 102700, 6, 6 }, /* 121.5 Mb*/ - [45] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000, - 112000, 7, 7 }, /* 135 Mb */ - [46] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, - 122000, 7, 7 }, /* 150 Mb */ - [47] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000, - 25800, 8, 8 }, /* 27 Mb */ - [48] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000, - 49800, 9, 9 }, /* 54 Mb */ - [49] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000, - 71900, 10, 10 }, /* 81 Mb */ - [50] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000, - 92500, 11, 11 }, /* 108 Mb */ - [51] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000, - 130300, 12, 12 }, /* 162 Mb */ - [52] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000, - 162800, 13, 13 }, /* 216 Mb */ - [53] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000, - 178200, 14, 14 }, /* 243 Mb */ - [54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000, - 192100, 15, 15 }, /* 270 Mb */ - [55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000, - 207000, 15, 15 }, /* 300 Mb */ - [56] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500, - 36100, 16, 16 }, /* 40.5 Mb */ - [57] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000, - 72900, 17, 17 }, /* 81 Mb */ - [58] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500, - 108300, 18, 18 }, /* 121.5 Mb */ - [59] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000, - 142000, 19, 19 }, /* 162 Mb */ - [60] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000, - 205100, 20, 20 }, /* 243 Mb */ - [61] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000, - 224700, 20, 20 }, /* 270 Mb */ - [62] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000, - 263100, 21, 21 }, /* 324 Mb */ - [63] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000, - 288000, 21, 21 }, /* 360 Mb */ - [64] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500, - 290700, 22, 22 }, /* 364.5 Mb */ - [65] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000, - 317200, 22, 22 }, /* 405 Mb */ - [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000, - 317200, 23, 23 }, /* 405 Mb */ - [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000, - 346400, 23, 23 }, /* 450 Mb */ - }, - 50, /* probe interval */ - WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ -}; - -/* 4ms frame limit not used for NG mode. The values filled - * for HT are the 64K max aggregate limit */ - -static const struct ath_rate_table ar5416_11ng_ratetable = { - 72, - 12, /* MCS start */ - { - [0] = { RC_ALL, WLAN_RC_PHY_CCK, 1000, - 900, 0, 2 }, /* 1 Mb */ - [1] = { RC_ALL, WLAN_RC_PHY_CCK, 2000, - 1900, 1, 4 }, /* 2 Mb */ - [2] = { RC_ALL, WLAN_RC_PHY_CCK, 5500, - 4900, 2, 11 }, /* 5.5 Mb */ - [3] = { RC_ALL, WLAN_RC_PHY_CCK, 11000, - 8100, 3, 22 }, /* 11 Mb */ - [4] = { RC_INVALID, WLAN_RC_PHY_OFDM, 6000, - 5400, 4, 12 }, /* 6 Mb */ - [5] = { RC_INVALID, WLAN_RC_PHY_OFDM, 9000, - 7800, 5, 18 }, /* 9 Mb */ - [6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, - 10100, 6, 24 }, /* 12 Mb */ - [7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, - 14100, 7, 36 }, /* 18 Mb */ - [8] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, - 17700, 8, 48 }, /* 24 Mb */ - [9] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, - 23700, 9, 72 }, /* 36 Mb */ - [10] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, - 27400, 10, 96 }, /* 48 Mb */ - [11] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, - 30900, 11, 108 }, /* 54 Mb */ - [12] = { RC_INVALID, WLAN_RC_PHY_HT_20_SS, 6500, - 6400, 0, 0 }, /* 6.5 Mb */ - [13] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000, - 12700, 1, 1 }, /* 13 Mb */ - [14] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500, - 18800, 2, 2 }, /* 19.5 Mb*/ - [15] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000, - 25000, 3, 3 }, /* 26 Mb */ - [16] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000, - 36700, 4, 4 }, /* 39 Mb */ - [17] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000, - 48100, 5, 5 }, /* 52 Mb */ - [18] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500, - 53500, 6, 6 }, /* 58.5 Mb */ - [19] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000, - 59000, 7, 7 }, /* 65 Mb */ - [20] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200, - 65400, 7, 7 }, /* 65 Mb*/ - [21] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000, - 12700, 8, 8 }, /* 13 Mb */ - [22] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000, - 24800, 9, 9 }, /* 26 Mb */ - [23] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000, - 36600, 10, 10 }, /* 39 Mb */ - [24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000, - 48100, 11, 11 }, /* 52 Mb */ - [25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000, - 69500, 12, 12 }, /* 78 Mb */ - [26] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000, - 89500, 13, 13 }, /* 104 Mb */ - [27] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000, - 98900, 14, 14 }, /* 117 Mb */ - [28] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000, - 108300, 15, 15 }, /* 130 Mb */ - [29] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400, - 120000, 15, 15 }, /* 144.4 Mb */ - [30] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500, - 17400, 16, 16 }, /* 19.5 Mb */ - [31] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000, - 35100, 17, 17 }, /* 39 Mb */ - [32] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500, - 52600, 18, 18 }, /* 58.5 Mb */ - [33] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000, - 70400, 19, 19 }, /* 78 Mb */ - [34] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000, - 104900, 20, 20 }, /* 117 Mb */ - [35] = { RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000, - 115800, 20, 20 }, /* 130 Mb */ - [36] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000, - 137200, 21, 21 }, /* 156 Mb */ - [37] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300, - 151100, 21, 21 }, /* 173.3 Mb */ - [38] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500, - 152800, 22, 22 }, /* 175.5 Mb */ - [39] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000, - 168400, 22, 22 }, /* 195 Mb */ - [40] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000, - 168400, 23, 23 }, /* 195 Mb */ - [41] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700, - 185000, 23, 23 }, /* 216.7 Mb */ - [42] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500, - 13200, 0, 0 }, /* 13.5 Mb */ - [43] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500, - 25900, 1, 1 }, /* 27.0 Mb */ - [44] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500, - 38600, 2, 2 }, /* 40.5 Mb */ - [45] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000, - 49800, 3, 3 }, /* 54 Mb */ - [46] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500, - 72200, 4, 4 }, /* 81 Mb */ - [47] = { RC_HT_S_40 , WLAN_RC_PHY_HT_40_SS, 108000, - 92900, 5, 5 }, /* 108 Mb */ - [48] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500, - 102700, 6, 6 }, /* 121.5 Mb */ - [49] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000, - 112000, 7, 7 }, /* 135 Mb */ - [50] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, - 122000, 7, 7 }, /* 150 Mb */ - [51] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000, - 25800, 8, 8 }, /* 27 Mb */ - [52] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000, - 49800, 9, 9 }, /* 54 Mb */ - [53] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000, - 71900, 10, 10 }, /* 81 Mb */ - [54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000, - 92500, 11, 11 }, /* 108 Mb */ - [55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000, - 130300, 12, 12 }, /* 162 Mb */ - [56] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000, - 162800, 13, 13 }, /* 216 Mb */ - [57] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000, - 178200, 14, 14 }, /* 243 Mb */ - [58] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000, - 192100, 15, 15 }, /* 270 Mb */ - [59] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000, - 207000, 15, 15 }, /* 300 Mb */ - [60] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500, - 36100, 16, 16 }, /* 40.5 Mb */ - [61] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000, - 72900, 17, 17 }, /* 81 Mb */ - [62] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500, - 108300, 18, 18 }, /* 121.5 Mb */ - [63] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000, - 142000, 19, 19 }, /* 162 Mb */ - [64] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000, - 205100, 20, 20 }, /* 243 Mb */ - [65] = { RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000, - 224700, 20, 20 }, /* 270 Mb */ - [66] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000, - 263100, 21, 21 }, /* 324 Mb */ - [67] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000, - 288000, 21, 21 }, /* 360 Mb */ - [68] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500, - 290700, 22, 22 }, /* 364.5 Mb */ - [69] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000, - 317200, 22, 22 }, /* 405 Mb */ - [70] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000, - 317200, 23, 23 }, /* 405 Mb */ - [71] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000, - 346400, 23, 23 }, /* 450 Mb */ - }, - 50, /* probe interval */ - WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ -}; - -static const struct ath_rate_table ar5416_11a_ratetable = { - 8, - 0, - { - { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 0, 12}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 1, 18}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 2, 24}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 3, 36}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 4, 48}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 5, 72}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 6, 96}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 7, 108}, - }, - 50, /* probe interval */ - 0, /* Phy rates allowed initially */ -}; - -static const struct ath_rate_table ar5416_11g_ratetable = { - 12, - 0, - { - { RC_L_SDT, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ - 900, 0, 2}, - { RC_L_SDT, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ - 1900, 1, 4}, - { RC_L_SDT, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ - 4900, 2, 11}, - { RC_L_SDT, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ - 8100, 3, 22}, - { RC_INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ - 5400, 4, 12}, - { RC_INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ - 7800, 5, 18}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ - 10000, 6, 24}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ - 13900, 7, 36}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ - 17300, 8, 48}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ - 23000, 9, 72}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ - 27400, 10, 96}, - { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ - 29300, 11, 108}, - }, - 50, /* probe interval */ - 0, /* Phy rates allowed initially */ -}; - -static int ath_rc_get_rateindex(struct ath_rate_priv *ath_rc_priv, - struct ieee80211_tx_rate *rate) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - int rix, i, idx = 0; - - if (!(rate->flags & IEEE80211_TX_RC_MCS)) - return rate->idx; - - for (i = 0; i < ath_rc_priv->max_valid_rate; i++) { - idx = ath_rc_priv->valid_rate_index[i]; - - if (WLAN_RC_PHY_HT(rate_table->info[idx].phy) && - rate_table->info[idx].ratecode == rate->idx) - break; - } - - rix = idx; - - if (rate->flags & IEEE80211_TX_RC_SHORT_GI) - rix++; - - return rix; -} - -static void ath_rc_sort_validrates(struct ath_rate_priv *ath_rc_priv) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - u8 i, j, idx, idx_next; - - for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) { - for (j = 0; j <= i-1; j++) { - idx = ath_rc_priv->valid_rate_index[j]; - idx_next = ath_rc_priv->valid_rate_index[j+1]; - - if (rate_table->info[idx].ratekbps > - rate_table->info[idx_next].ratekbps) { - ath_rc_priv->valid_rate_index[j] = idx_next; - ath_rc_priv->valid_rate_index[j+1] = idx; - } - } - } -} - -static inline -int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv, - u8 cur_valid_txrate, - u8 *next_idx) -{ - u8 i; - - for (i = 0; i < ath_rc_priv->max_valid_rate - 1; i++) { - if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { - *next_idx = ath_rc_priv->valid_rate_index[i+1]; - return 1; - } - } - - /* No more valid rates */ - *next_idx = 0; - - return 0; -} - -/* Return true only for single stream */ - -static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) -{ - if (WLAN_RC_PHY_HT(phy) && !(capflag & WLAN_RC_HT_FLAG)) - return 0; - if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG)) - return 0; - if (WLAN_RC_PHY_TS(phy) && !(capflag & WLAN_RC_TS_FLAG)) - return 0; - if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG)) - return 0; - if (!ignore_cw && WLAN_RC_PHY_HT(phy)) - if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG)) - return 0; - return 1; -} - -static inline int -ath_rc_get_lower_rix(struct ath_rate_priv *ath_rc_priv, - u8 cur_valid_txrate, u8 *next_idx) -{ - int8_t i; - - for (i = 1; i < ath_rc_priv->max_valid_rate ; i++) { - if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { - *next_idx = ath_rc_priv->valid_rate_index[i-1]; - return 1; - } - } - - return 0; -} - -static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - u8 i, hi = 0; - - for (i = 0; i < rate_table->rate_cnt; i++) { - if (rate_table->info[i].rate_flags & RC_LEGACY) { - u32 phy = rate_table->info[i].phy; - u8 valid_rate_count = 0; - - if (!ath_rc_valid_phyrate(phy, ath_rc_priv->ht_cap, 0)) - continue; - - valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy]; - - ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i; - ath_rc_priv->valid_phy_ratecnt[phy] += 1; - ath_rc_priv->valid_rate_index[i] = true; - hi = i; - } - } - - return hi; -} - -static inline bool ath_rc_check_legacy(u8 rate, u8 dot11rate, u16 rate_flags, - u32 phy, u32 capflag) -{ - if (rate != dot11rate || WLAN_RC_PHY_HT(phy)) - return false; - - if ((rate_flags & WLAN_RC_CAP_MODE(capflag)) != WLAN_RC_CAP_MODE(capflag)) - return false; - - if (!(rate_flags & WLAN_RC_CAP_STREAM(capflag))) - return false; - - return true; -} - -static inline bool ath_rc_check_ht(u8 rate, u8 dot11rate, u16 rate_flags, - u32 phy, u32 capflag) -{ - if (rate != dot11rate || !WLAN_RC_PHY_HT(phy)) - return false; - - if (!WLAN_RC_PHY_HT_VALID(rate_flags, capflag)) - return false; - - if (!(rate_flags & WLAN_RC_CAP_STREAM(capflag))) - return false; - - return true; -} - -static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, bool legacy) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - struct ath_rateset *rateset; - u32 phy, capflag = ath_rc_priv->ht_cap; - u16 rate_flags; - u8 i, j, hi = 0, rate, dot11rate, valid_rate_count; - - if (legacy) - rateset = &ath_rc_priv->neg_rates; - else - rateset = &ath_rc_priv->neg_ht_rates; - - for (i = 0; i < rateset->rs_nrates; i++) { - for (j = 0; j < rate_table->rate_cnt; j++) { - phy = rate_table->info[j].phy; - rate_flags = rate_table->info[j].rate_flags; - rate = rateset->rs_rates[i]; - dot11rate = rate_table->info[j].dot11rate; - - if (legacy && - !ath_rc_check_legacy(rate, dot11rate, - rate_flags, phy, capflag)) - continue; - - if (!legacy && - !ath_rc_check_ht(rate, dot11rate, - rate_flags, phy, capflag)) - continue; - - if (!ath_rc_valid_phyrate(phy, capflag, 0)) - continue; - - valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy]; - ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = j; - ath_rc_priv->valid_phy_ratecnt[phy] += 1; - ath_rc_priv->valid_rate_index[j] = true; - hi = max(hi, j); - } - } - - return hi; -} - -static u8 ath_rc_get_highest_rix(struct ath_rate_priv *ath_rc_priv, - int *is_probing) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - u32 best_thruput, this_thruput, now_msec; - u8 rate, next_rate, best_rate, maxindex, minindex; - int8_t index = 0; - - now_msec = jiffies_to_msecs(jiffies); - *is_probing = 0; - best_thruput = 0; - maxindex = ath_rc_priv->max_valid_rate-1; - minindex = 0; - best_rate = minindex; - - /* - * Try the higher rate first. It will reduce memory moving time - * if we have very good channel characteristics. - */ - for (index = maxindex; index >= minindex ; index--) { - u8 per_thres; - - rate = ath_rc_priv->valid_rate_index[index]; - if (rate > ath_rc_priv->rate_max_phy) - continue; - - /* - * For TCP the average collision rate is around 11%, - * so we ignore PERs less than this. This is to - * prevent the rate we are currently using (whose - * PER might be in the 10-15 range because of TCP - * collisions) looking worse than the next lower - * rate whose PER has decayed close to 0. If we - * used to next lower rate, its PER would grow to - * 10-15 and we would be worse off then staying - * at the current rate. - */ - per_thres = ath_rc_priv->per[rate]; - if (per_thres < 12) - per_thres = 12; - - this_thruput = rate_table->info[rate].user_ratekbps * - (100 - per_thres); - - if (best_thruput <= this_thruput) { - best_thruput = this_thruput; - best_rate = rate; - } - } - - rate = best_rate; - - /* - * Must check the actual rate (ratekbps) to account for - * non-monoticity of 11g's rate table - */ - - if (rate >= ath_rc_priv->rate_max_phy) { - rate = ath_rc_priv->rate_max_phy; - - /* Probe the next allowed phy state */ - if (ath_rc_get_nextvalid_txrate(rate_table, - ath_rc_priv, rate, &next_rate) && - (now_msec - ath_rc_priv->probe_time > - rate_table->probe_interval) && - (ath_rc_priv->hw_maxretry_pktcnt >= 1)) { - rate = next_rate; - ath_rc_priv->probe_rate = rate; - ath_rc_priv->probe_time = now_msec; - ath_rc_priv->hw_maxretry_pktcnt = 0; - *is_probing = 1; - } - } - - if (rate > (ath_rc_priv->rate_table_size - 1)) - rate = ath_rc_priv->rate_table_size - 1; - - if (RC_TS_ONLY(rate_table->info[rate].rate_flags) && - (ath_rc_priv->ht_cap & WLAN_RC_TS_FLAG)) - return rate; - - if (RC_DS_OR_LATER(rate_table->info[rate].rate_flags) && - (ath_rc_priv->ht_cap & (WLAN_RC_DS_FLAG | WLAN_RC_TS_FLAG))) - return rate; - - if (RC_SS_OR_LEGACY(rate_table->info[rate].rate_flags)) - return rate; - - /* This should not happen */ - WARN_ON_ONCE(1); - - rate = ath_rc_priv->valid_rate_index[0]; - - return rate; -} - -static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table, - struct ieee80211_tx_rate *rate, - struct ieee80211_tx_rate_control *txrc, - u8 tries, u8 rix, int rtsctsenable) -{ - rate->count = tries; - rate->idx = rate_table->info[rix].ratecode; - - if (txrc->rts || rtsctsenable) - rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; - - if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) { - rate->flags |= IEEE80211_TX_RC_MCS; - if (WLAN_RC_PHY_40(rate_table->info[rix].phy) && - conf_is_ht40(&txrc->hw->conf)) - rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy)) - rate->flags |= IEEE80211_TX_RC_SHORT_GI; - } -} - -static void ath_rc_rate_set_rtscts(struct ath_softc *sc, - const struct ath_rate_table *rate_table, - struct ieee80211_tx_info *tx_info) -{ - struct ieee80211_bss_conf *bss_conf; - - if (!tx_info->control.vif) - return; - /* - * For legacy frames, mac80211 takes care of CTS protection. - */ - if (!(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)) - return; - - bss_conf = &tx_info->control.vif->bss_conf; - - if (!bss_conf->basic_rates) - return; - - /* - * For now, use the lowest allowed basic rate for HT frames. - */ - tx_info->control.rts_cts_rate_idx = __ffs(bss_conf->basic_rates); -} - -static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, - struct ieee80211_tx_rate_control *txrc) -{ - struct ath_softc *sc = priv; - struct ath_rate_priv *ath_rc_priv = priv_sta; - const struct ath_rate_table *rate_table; - struct sk_buff *skb = txrc->skb; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rates = tx_info->control.rates; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc = hdr->frame_control; - u8 try_per_rate, i = 0, rix; - int is_probe = 0; - - if (rate_control_send_low(sta, priv_sta, txrc)) - return; - - /* - * For Multi Rate Retry we use a different number of - * retry attempt counts. This ends up looking like this: - * - * MRR[0] = 4 - * MRR[1] = 4 - * MRR[2] = 4 - * MRR[3] = 8 - * - */ - try_per_rate = 4; - - rate_table = ath_rc_priv->rate_table; - rix = ath_rc_get_highest_rix(ath_rc_priv, &is_probe); - - if (conf_is_ht(&sc->hw->conf) && - (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)) - tx_info->flags |= IEEE80211_TX_CTL_LDPC; - - if (conf_is_ht(&sc->hw->conf) && - (sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) - tx_info->flags |= (1 << IEEE80211_TX_CTL_STBC_SHIFT); - - if (is_probe) { - /* - * Set one try for probe rates. For the - * probes don't enable RTS. - */ - ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - 1, rix, 0); - /* - * Get the next tried/allowed rate. - * No RTS for the next series after the probe rate. - */ - ath_rc_get_lower_rix(ath_rc_priv, rix, &rix); - ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - try_per_rate, rix, 0); - - tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; - } else { - /* - * Set the chosen rate. No RTS for first series entry. - */ - ath_rc_rate_set_series(rate_table, &rates[i++], txrc, - try_per_rate, rix, 0); - } - - for ( ; i < 4; i++) { - /* - * Use twice the number of tries for the last MRR segment. - */ - if (i + 1 == 4) - try_per_rate = 8; - - ath_rc_get_lower_rix(ath_rc_priv, rix, &rix); - - /* - * All other rates in the series have RTS enabled. - */ - ath_rc_rate_set_series(rate_table, &rates[i], txrc, - try_per_rate, rix, 1); - } - - /* - * NB:Change rate series to enable aggregation when operating - * at lower MCS rates. When first rate in series is MCS2 - * in HT40 @ 2.4GHz, series should look like: - * - * {MCS2, MCS1, MCS0, MCS0}. - * - * When first rate in series is MCS3 in HT20 @ 2.4GHz, series should - * look like: - * - * {MCS3, MCS2, MCS1, MCS1} - * - * So, set fourth rate in series to be same as third one for - * above conditions. - */ - if ((sc->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ) && - (conf_is_ht(&sc->hw->conf))) { - u8 dot11rate = rate_table->info[rix].dot11rate; - u8 phy = rate_table->info[rix].phy; - if (i == 4 && - ((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) || - (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) { - rates[3].idx = rates[2].idx; - rates[3].flags = rates[2].flags; - } - } - - /* - * Force hardware to use computed duration for next - * fragment by disabling multi-rate retry, which - * updates duration based on the multi-rate duration table. - * - * FIXME: Fix duration - */ - if (ieee80211_has_morefrags(fc) || - (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { - rates[1].count = rates[2].count = rates[3].count = 0; - rates[1].idx = rates[2].idx = rates[3].idx = 0; - rates[0].count = ATH_TXMAXTRY; - } - - ath_rc_rate_set_rtscts(sc, rate_table, tx_info); -} - -static void ath_rc_update_per(struct ath_softc *sc, - const struct ath_rate_table *rate_table, - struct ath_rate_priv *ath_rc_priv, - struct ieee80211_tx_info *tx_info, - int tx_rate, int xretries, int retries, - u32 now_msec) -{ - int count, n_bad_frames; - u8 last_per; - static const u32 nretry_to_per_lookup[10] = { - 100 * 0 / 1, - 100 * 1 / 4, - 100 * 1 / 2, - 100 * 3 / 4, - 100 * 4 / 5, - 100 * 5 / 6, - 100 * 6 / 7, - 100 * 7 / 8, - 100 * 8 / 9, - 100 * 9 / 10 - }; - - last_per = ath_rc_priv->per[tx_rate]; - n_bad_frames = tx_info->status.ampdu_len - tx_info->status.ampdu_ack_len; - - if (xretries) { - if (xretries == 1) { - ath_rc_priv->per[tx_rate] += 30; - if (ath_rc_priv->per[tx_rate] > 100) - ath_rc_priv->per[tx_rate] = 100; - } else { - /* xretries == 2 */ - count = ARRAY_SIZE(nretry_to_per_lookup); - if (retries >= count) - retries = count - 1; - - /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ - ath_rc_priv->per[tx_rate] = - (u8)(last_per - (last_per >> 3) + (100 >> 3)); - } - - /* xretries == 1 or 2 */ - - if (ath_rc_priv->probe_rate == tx_rate) - ath_rc_priv->probe_rate = 0; - - } else { /* xretries == 0 */ - count = ARRAY_SIZE(nretry_to_per_lookup); - if (retries >= count) - retries = count - 1; - - if (n_bad_frames) { - /* new_PER = 7/8*old_PER + 1/8*(currentPER) - * Assuming that n_frames is not 0. The current PER - * from the retries is 100 * retries / (retries+1), - * since the first retries attempts failed, and the - * next one worked. For the one that worked, - * n_bad_frames subframes out of n_frames wored, - * so the PER for that part is - * 100 * n_bad_frames / n_frames, and it contributes - * 100 * n_bad_frames / (n_frames * (retries+1)) to - * the above PER. The expression below is a - * simplified version of the sum of these two terms. - */ - if (tx_info->status.ampdu_len > 0) { - int n_frames, n_bad_tries; - u8 cur_per, new_per; - - n_bad_tries = retries * tx_info->status.ampdu_len + - n_bad_frames; - n_frames = tx_info->status.ampdu_len * (retries + 1); - cur_per = (100 * n_bad_tries / n_frames) >> 3; - new_per = (u8)(last_per - (last_per >> 3) + cur_per); - ath_rc_priv->per[tx_rate] = new_per; - } - } else { - ath_rc_priv->per[tx_rate] = - (u8)(last_per - (last_per >> 3) + - (nretry_to_per_lookup[retries] >> 3)); - } - - - /* - * If we got at most one retry then increase the max rate if - * this was a probe. Otherwise, ignore the probe. - */ - if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) { - if (retries > 0 || 2 * n_bad_frames > tx_info->status.ampdu_len) { - /* - * Since we probed with just a single attempt, - * any retries means the probe failed. Also, - * if the attempt worked, but more than half - * the subframes were bad then also consider - * the probe a failure. - */ - ath_rc_priv->probe_rate = 0; - } else { - u8 probe_rate = 0; - - ath_rc_priv->rate_max_phy = - ath_rc_priv->probe_rate; - probe_rate = ath_rc_priv->probe_rate; - - if (ath_rc_priv->per[probe_rate] > 30) - ath_rc_priv->per[probe_rate] = 20; - - ath_rc_priv->probe_rate = 0; - - /* - * Since this probe succeeded, we allow the next - * probe twice as soon. This allows the maxRate - * to move up faster if the probes are - * successful. - */ - ath_rc_priv->probe_time = - now_msec - rate_table->probe_interval / 2; - } - } - - if (retries > 0) { - /* - * Don't update anything. We don't know if - * this was because of collisions or poor signal. - */ - ath_rc_priv->hw_maxretry_pktcnt = 0; - } else { - /* - * It worked with no retries. First ignore bogus (small) - * rssi_ack values. - */ - if (tx_rate == ath_rc_priv->rate_max_phy && - ath_rc_priv->hw_maxretry_pktcnt < 255) { - ath_rc_priv->hw_maxretry_pktcnt++; - } - - } - } -} - -static void ath_rc_update_ht(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct ieee80211_tx_info *tx_info, - int tx_rate, int xretries, int retries) -{ - u32 now_msec = jiffies_to_msecs(jiffies); - int rate; - u8 last_per; - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - int size = ath_rc_priv->rate_table_size; - - if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) - return; - - last_per = ath_rc_priv->per[tx_rate]; - - /* Update PER first */ - ath_rc_update_per(sc, rate_table, ath_rc_priv, - tx_info, tx_rate, xretries, - retries, now_msec); - - /* - * If this rate looks bad (high PER) then stop using it for - * a while (except if we are probing). - */ - if (ath_rc_priv->per[tx_rate] >= 55 && tx_rate > 0 && - rate_table->info[tx_rate].ratekbps <= - rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) { - ath_rc_get_lower_rix(ath_rc_priv, (u8)tx_rate, - &ath_rc_priv->rate_max_phy); - - /* Don't probe for a little while. */ - ath_rc_priv->probe_time = now_msec; - } - - /* Make sure the rates below this have lower PER */ - /* Monotonicity is kept only for rates below the current rate. */ - if (ath_rc_priv->per[tx_rate] < last_per) { - for (rate = tx_rate - 1; rate >= 0; rate--) { - - if (ath_rc_priv->per[rate] > - ath_rc_priv->per[rate+1]) { - ath_rc_priv->per[rate] = - ath_rc_priv->per[rate+1]; - } - } - } - - /* Maintain monotonicity for rates above the current rate */ - for (rate = tx_rate; rate < size - 1; rate++) { - if (ath_rc_priv->per[rate+1] < - ath_rc_priv->per[rate]) - ath_rc_priv->per[rate+1] = - ath_rc_priv->per[rate]; - } - - /* Every so often, we reduce the thresholds - * and PER (different for CCK and OFDM). */ - if (now_msec - ath_rc_priv->per_down_time >= - rate_table->probe_interval) { - for (rate = 0; rate < size; rate++) { - ath_rc_priv->per[rate] = - 7 * ath_rc_priv->per[rate] / 8; - } - - ath_rc_priv->per_down_time = now_msec; - } - - ath_debug_stat_retries(ath_rc_priv, tx_rate, xretries, retries, - ath_rc_priv->per[tx_rate]); - -} - -static void ath_rc_tx_status(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv, - struct sk_buff *skb) -{ - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *rates = tx_info->status.rates; - struct ieee80211_tx_rate *rate; - int final_ts_idx = 0, xretries = 0, long_retry = 0; - u8 flags; - u32 i = 0, rix; - - for (i = 0; i < sc->hw->max_rates; i++) { - rate = &tx_info->status.rates[i]; - if (rate->idx < 0 || !rate->count) - break; - - final_ts_idx = i; - long_retry = rate->count - 1; - } - - if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) - xretries = 1; - - /* - * If the first rate is not the final index, there - * are intermediate rate failures to be processed. - */ - if (final_ts_idx != 0) { - for (i = 0; i < final_ts_idx ; i++) { - if (rates[i].count != 0 && (rates[i].idx >= 0)) { - flags = rates[i].flags; - - /* If HT40 and we have switched mode from - * 40 to 20 => don't update */ - - if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) - return; - - rix = ath_rc_get_rateindex(ath_rc_priv, &rates[i]); - ath_rc_update_ht(sc, ath_rc_priv, tx_info, - rix, xretries ? 1 : 2, - rates[i].count); - } - } - } - - flags = rates[final_ts_idx].flags; - - /* If HT40 and we have switched mode from 40 to 20 => don't update */ - if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && - !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG)) - return; - - rix = ath_rc_get_rateindex(ath_rc_priv, &rates[final_ts_idx]); - ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry); - ath_debug_stat_rc(ath_rc_priv, rix); -} - -static const -struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, - enum ieee80211_band band, - bool is_ht) -{ - switch(band) { - case IEEE80211_BAND_2GHZ: - if (is_ht) - return &ar5416_11ng_ratetable; - return &ar5416_11g_ratetable; - case IEEE80211_BAND_5GHZ: - if (is_ht) - return &ar5416_11na_ratetable; - return &ar5416_11a_ratetable; - default: - return NULL; - } -} - -static void ath_rc_init(struct ath_softc *sc, - struct ath_rate_priv *ath_rc_priv) -{ - const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; - struct ath_rateset *rateset = &ath_rc_priv->neg_rates; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - u8 i, j, k, hi = 0, hthi = 0; - - ath_rc_priv->rate_table_size = RATE_TABLE_SIZE; - - for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) { - ath_rc_priv->per[i] = 0; - ath_rc_priv->valid_rate_index[i] = 0; - } - - for (i = 0; i < WLAN_RC_PHY_MAX; i++) { - for (j = 0; j < RATE_TABLE_SIZE; j++) - ath_rc_priv->valid_phy_rateidx[i][j] = 0; - ath_rc_priv->valid_phy_ratecnt[i] = 0; - } - - if (!rateset->rs_nrates) { - hi = ath_rc_init_validrates(ath_rc_priv); - } else { - hi = ath_rc_setvalid_rates(ath_rc_priv, true); - - if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) - hthi = ath_rc_setvalid_rates(ath_rc_priv, false); - - hi = max(hi, hthi); - } - - ath_rc_priv->rate_table_size = hi + 1; - ath_rc_priv->rate_max_phy = 0; - WARN_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE); - - for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) { - for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) { - ath_rc_priv->valid_rate_index[k++] = - ath_rc_priv->valid_phy_rateidx[i][j]; - } - - if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1) || - !ath_rc_priv->valid_phy_ratecnt[i]) - continue; - - ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1]; - } - WARN_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE); - WARN_ON(k > RATE_TABLE_SIZE); - - ath_rc_priv->max_valid_rate = k; - ath_rc_sort_validrates(ath_rc_priv); - ath_rc_priv->rate_max_phy = (k > 4) ? - ath_rc_priv->valid_rate_index[k-4] : - ath_rc_priv->valid_rate_index[k-1]; - - ath_dbg(common, CONFIG, "RC Initialized with capabilities: 0x%x\n", - ath_rc_priv->ht_cap); -} - -static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta) -{ - u8 caps = 0; - - if (sta->ht_cap.ht_supported) { - caps = WLAN_RC_HT_FLAG; - if (sta->ht_cap.mcs.rx_mask[1] && sta->ht_cap.mcs.rx_mask[2]) - caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; - else if (sta->ht_cap.mcs.rx_mask[1]) - caps |= WLAN_RC_DS_FLAG; - if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) { - caps |= WLAN_RC_40_FLAG; - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) - caps |= WLAN_RC_SGI_FLAG; - } else { - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) - caps |= WLAN_RC_SGI_FLAG; - } - } - - return caps; -} - -static bool ath_tx_aggr_check(struct ath_softc *sc, struct ieee80211_sta *sta, - u8 tidno) -{ - struct ath_node *an = (struct ath_node *)sta->drv_priv; - struct ath_atx_tid *txtid; - - if (!sta->ht_cap.ht_supported) - return false; - - txtid = ATH_AN_2_TID(an, tidno); - return !txtid->active; -} - - -/***********************************/ -/* mac80211 Rate Control callbacks */ -/***********************************/ - -static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb) -{ - struct ath_softc *sc = priv; - struct ath_rate_priv *ath_rc_priv = priv_sta; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc = hdr->frame_control; - - if (!priv_sta || !ieee80211_is_data(fc)) - return; - - /* This packet was aggregated but doesn't carry status info */ - if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && - !(tx_info->flags & IEEE80211_TX_STAT_AMPDU)) - return; - - if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) - return; - - ath_rc_tx_status(sc, ath_rc_priv, skb); - - /* Check if aggregation has to be enabled for this tid */ - if (conf_is_ht(&sc->hw->conf) && - !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { - if (ieee80211_is_data_qos(fc) && - skb_get_queue_mapping(skb) != IEEE80211_AC_VO) { - u8 *qc, tid; - - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - - if(ath_tx_aggr_check(sc, sta, tid)) - ieee80211_start_tx_ba_session(sta, tid, 0); - } - } -} - -static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta) -{ - struct ath_softc *sc = priv; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_rate_priv *ath_rc_priv = priv_sta; - int i, j = 0; - - for (i = 0; i < sband->n_bitrates; i++) { - if (sta->supp_rates[sband->band] & BIT(i)) { - ath_rc_priv->neg_rates.rs_rates[j] - = (sband->bitrates[i].bitrate * 2) / 10; - j++; - } - } - ath_rc_priv->neg_rates.rs_nrates = j; - - if (sta->ht_cap.ht_supported) { - for (i = 0, j = 0; i < 77; i++) { - if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) - ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; - if (j == ATH_RATE_MAX) - break; - } - ath_rc_priv->neg_ht_rates.rs_nrates = j; - } - - ath_rc_priv->rate_table = ath_choose_rate_table(sc, sband->band, - sta->ht_cap.ht_supported); - if (!ath_rc_priv->rate_table) { - ath_err(common, "No rate table chosen\n"); - return; - } - - ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta); - ath_rc_init(sc, priv_sta); -} - -static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - u32 changed) -{ - struct ath_softc *sc = priv; - struct ath_rate_priv *ath_rc_priv = priv_sta; - - if (changed & IEEE80211_RC_BW_CHANGED) { - ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta); - ath_rc_init(sc, priv_sta); - - ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG, - "Operating HT Bandwidth changed to: %d\n", - cfg80211_get_chandef_type(&sc->hw->conf.chandef)); - } -} - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) - -void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) -{ - struct ath_rc_stats *stats; - - stats = &rc->rcstats[final_rate]; - stats->success++; -} - -void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, - int xretries, int retries, u8 per) -{ - struct ath_rc_stats *stats = &rc->rcstats[rix]; - - stats->xretries += xretries; - stats->retries += retries; - stats->per = per; -} - -static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ath_rate_priv *rc = file->private_data; - char *buf; - unsigned int len = 0, max; - int rix; - ssize_t retval; - - if (rc->rate_table == NULL) - return 0; - - max = 80 + rc->rate_table_size * 1024 + 1; - buf = kmalloc(max, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - len += sprintf(buf, "%6s %6s %6s " - "%10s %10s %10s %10s\n", - "HT", "MCS", "Rate", - "Success", "Retries", "XRetries", "PER"); - - for (rix = 0; rix < rc->max_valid_rate; rix++) { - u8 i = rc->valid_rate_index[rix]; - u32 ratekbps = rc->rate_table->info[i].ratekbps; - struct ath_rc_stats *stats = &rc->rcstats[i]; - char mcs[5]; - char htmode[5]; - int used_mcs = 0, used_htmode = 0; - - if (WLAN_RC_PHY_HT(rc->rate_table->info[i].phy)) { - used_mcs = snprintf(mcs, 5, "%d", - rc->rate_table->info[i].ratecode); - - if (WLAN_RC_PHY_40(rc->rate_table->info[i].phy)) - used_htmode = snprintf(htmode, 5, "HT40"); - else if (WLAN_RC_PHY_20(rc->rate_table->info[i].phy)) - used_htmode = snprintf(htmode, 5, "HT20"); - else - used_htmode = snprintf(htmode, 5, "????"); - } - - mcs[used_mcs] = '\0'; - htmode[used_htmode] = '\0'; - - len += snprintf(buf + len, max - len, - "%6s %6s %3u.%d: " - "%10u %10u %10u %10u\n", - htmode, - mcs, - ratekbps / 1000, - (ratekbps % 1000) / 100, - stats->success, - stats->retries, - stats->xretries, - stats->per); - } - - if (len > max) - len = max; - - retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); - kfree(buf); - return retval; -} - -static const struct file_operations fops_rcstat = { - .read = read_file_rcstat, - .open = simple_open, - .owner = THIS_MODULE -}; - -static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta, - struct dentry *dir) -{ - struct ath_rate_priv *rc = priv_sta; - rc->debugfs_rcstats = debugfs_create_file("rc_stats", S_IRUGO, - dir, rc, &fops_rcstat); -} - -static void ath_rate_remove_sta_debugfs(void *priv, void *priv_sta) -{ - struct ath_rate_priv *rc = priv_sta; - debugfs_remove(rc->debugfs_rcstats); -} - -#endif /* CONFIG_MAC80211_DEBUGFS && CONFIG_ATH9K_DEBUGFS */ - -static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) -{ - return hw->priv; -} - -static void ath_rate_free(void *priv) -{ - return; -} - -static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) -{ - return kzalloc(sizeof(struct ath_rate_priv), gfp); -} - -static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta, - void *priv_sta) -{ - struct ath_rate_priv *rate_priv = priv_sta; - kfree(rate_priv); -} - -static struct rate_control_ops ath_rate_ops = { - .module = NULL, - .name = "ath9k_rate_control", - .tx_status = ath_tx_status, - .get_rate = ath_get_rate, - .rate_init = ath_rate_init, - .rate_update = ath_rate_update, - .alloc = ath_rate_alloc, - .free = ath_rate_free, - .alloc_sta = ath_rate_alloc_sta, - .free_sta = ath_rate_free_sta, - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) - .add_sta_debugfs = ath_rate_add_sta_debugfs, - .remove_sta_debugfs = ath_rate_remove_sta_debugfs, -#endif -}; - -int ath_rate_control_register(void) -{ - return ieee80211_rate_control_register(&ath_rate_ops); -} - -void ath_rate_control_unregister(void) -{ - ieee80211_rate_control_unregister(&ath_rate_ops); -} diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h deleted file mode 100644 index b9a87383cb43..000000000000 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2004 Sam Leffler, Errno Consulting - * Copyright (c) 2004 Video54 Technologies, Inc. - * Copyright (c) 2008-2011 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef RC_H -#define RC_H - -#include "hw.h" - -struct ath_softc; - -#define ATH_RATE_MAX 30 -#define RATE_TABLE_SIZE 72 - -#define RC_INVALID 0x0000 -#define RC_LEGACY 0x0001 -#define RC_SS 0x0002 -#define RC_DS 0x0004 -#define RC_TS 0x0008 -#define RC_HT_20 0x0010 -#define RC_HT_40 0x0020 - -#define RC_STREAM_MASK 0xe -#define RC_DS_OR_LATER(f) ((((f) & RC_STREAM_MASK) == RC_DS) || \ - (((f) & RC_STREAM_MASK) == (RC_DS | RC_TS))) -#define RC_TS_ONLY(f) (((f) & RC_STREAM_MASK) == RC_TS) -#define RC_SS_OR_LEGACY(f) ((f) & (RC_SS | RC_LEGACY)) - -#define RC_HT_2040 (RC_HT_20 | RC_HT_40) -#define RC_ALL_STREAM (RC_SS | RC_DS | RC_TS) -#define RC_L_SD (RC_LEGACY | RC_SS | RC_DS) -#define RC_L_SDT (RC_LEGACY | RC_SS | RC_DS | RC_TS) -#define RC_HT_S_20 (RC_HT_20 | RC_SS) -#define RC_HT_D_20 (RC_HT_20 | RC_DS) -#define RC_HT_T_20 (RC_HT_20 | RC_TS) -#define RC_HT_S_40 (RC_HT_40 | RC_SS) -#define RC_HT_D_40 (RC_HT_40 | RC_DS) -#define RC_HT_T_40 (RC_HT_40 | RC_TS) - -#define RC_HT_SD_20 (RC_HT_20 | RC_SS | RC_DS) -#define RC_HT_DT_20 (RC_HT_20 | RC_DS | RC_TS) -#define RC_HT_SD_40 (RC_HT_40 | RC_SS | RC_DS) -#define RC_HT_DT_40 (RC_HT_40 | RC_DS | RC_TS) - -#define RC_HT_SD_2040 (RC_HT_2040 | RC_SS | RC_DS) -#define RC_HT_SDT_2040 (RC_HT_2040 | RC_SS | RC_DS | RC_TS) - -#define RC_HT_SDT_20 (RC_HT_20 | RC_SS | RC_DS | RC_TS) -#define RC_HT_SDT_40 (RC_HT_40 | RC_SS | RC_DS | RC_TS) - -#define RC_ALL (RC_LEGACY | RC_HT_2040 | RC_ALL_STREAM) - -enum { - WLAN_RC_PHY_OFDM, - WLAN_RC_PHY_CCK, - WLAN_RC_PHY_HT_20_SS, - WLAN_RC_PHY_HT_20_DS, - WLAN_RC_PHY_HT_20_TS, - WLAN_RC_PHY_HT_40_SS, - WLAN_RC_PHY_HT_40_DS, - WLAN_RC_PHY_HT_40_TS, - WLAN_RC_PHY_HT_20_SS_HGI, - WLAN_RC_PHY_HT_20_DS_HGI, - WLAN_RC_PHY_HT_20_TS_HGI, - WLAN_RC_PHY_HT_40_SS_HGI, - WLAN_RC_PHY_HT_40_DS_HGI, - WLAN_RC_PHY_HT_40_TS_HGI, - WLAN_RC_PHY_MAX -}; - -#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \ - || (_phy == WLAN_RC_PHY_HT_40_DS) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) -#define WLAN_RC_PHY_TS(_phy) ((_phy == WLAN_RC_PHY_HT_20_TS) \ - || (_phy == WLAN_RC_PHY_HT_40_TS) \ - || (_phy == WLAN_RC_PHY_HT_20_TS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_TS_HGI)) -#define WLAN_RC_PHY_20(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS) \ - || (_phy == WLAN_RC_PHY_HT_20_DS) \ - || (_phy == WLAN_RC_PHY_HT_20_TS) \ - || (_phy == WLAN_RC_PHY_HT_20_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_TS_HGI)) -#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \ - || (_phy == WLAN_RC_PHY_HT_40_DS) \ - || (_phy == WLAN_RC_PHY_HT_40_TS) \ - || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_TS_HGI)) -#define WLAN_RC_PHY_SGI(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_TS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_TS_HGI)) - -#define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS) - -#define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ? \ - ((capflag & WLAN_RC_40_FLAG) ? RC_HT_40 : RC_HT_20) : RC_LEGACY)) - -#define WLAN_RC_CAP_STREAM(capflag) (((capflag & WLAN_RC_TS_FLAG) ? \ - (RC_TS) : ((capflag & WLAN_RC_DS_FLAG) ? RC_DS : RC_SS))) - -/* Return TRUE if flag supports HT20 && client supports HT20 or - * return TRUE if flag supports HT40 && client supports HT40. - * This is used becos some rates overlap between HT20/HT40. - */ -#define WLAN_RC_PHY_HT_VALID(flag, capflag) \ - (((flag & RC_HT_20) && !(capflag & WLAN_RC_40_FLAG)) || \ - ((flag & RC_HT_40) && (capflag & WLAN_RC_40_FLAG))) - -#define WLAN_RC_DS_FLAG (0x01) -#define WLAN_RC_TS_FLAG (0x02) -#define WLAN_RC_40_FLAG (0x04) -#define WLAN_RC_SGI_FLAG (0x08) -#define WLAN_RC_HT_FLAG (0x10) - -/** - * struct ath_rate_table - Rate Control table - * @rate_cnt: total number of rates for the given wireless mode - * @mcs_start: MCS rate index offset - * @rate_flags: Rate Control flags - * @phy: CCK/OFDM/HT20/HT40 - * @ratekbps: rate in Kbits per second - * @user_ratekbps: user rate in Kbits per second - * @ratecode: rate that goes into HW descriptors - * @dot11rate: value that goes into supported - * rates info element of MLME - * @ctrl_rate: Index of next lower basic rate, used for duration computation - * @cw40index: Index of rates having 40MHz channel width - * @sgi_index: Index of rates having Short Guard Interval - * @ht_index: high throughput rates having 40MHz channel width and - * Short Guard Interval - * @probe_interval: interval for rate control to probe for other rates - * @initial_ratemax: initial ratemax value - */ -struct ath_rate_table { - int rate_cnt; - int mcs_start; - struct { - u16 rate_flags; - u8 phy; - u32 ratekbps; - u32 user_ratekbps; - u8 ratecode; - u8 dot11rate; - } info[RATE_TABLE_SIZE]; - u32 probe_interval; - u8 initial_ratemax; -}; - -struct ath_rateset { - u8 rs_nrates; - u8 rs_rates[ATH_RATE_MAX]; -}; - -struct ath_rc_stats { - u32 success; - u32 retries; - u32 xretries; - u8 per; -}; - -/** - * struct ath_rate_priv - Rate Control priv data - * @state: RC state - * @probe_rate: rate we are probing at - * @probe_time: msec timestamp for last probe - * @hw_maxretry_pktcnt: num of packets since we got HW max retry error - * @max_valid_rate: maximum number of valid rate - * @per_down_time: msec timestamp for last PER down step - * @valid_phy_ratecnt: valid rate count - * @rate_max_phy: phy index for the max rate - * @per: PER for every valid rate in % - * @probe_interval: interval for ratectrl to probe for other rates - * @ht_cap: HT capabilities - * @neg_rates: Negotatied rates - * @neg_ht_rates: Negotiated HT rates - */ -struct ath_rate_priv { - u8 rate_table_size; - u8 probe_rate; - u8 hw_maxretry_pktcnt; - u8 max_valid_rate; - u8 valid_rate_index[RATE_TABLE_SIZE]; - u8 ht_cap; - u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; - u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; - u8 rate_max_phy; - u8 per[RATE_TABLE_SIZE]; - u32 probe_time; - u32 per_down_time; - u32 probe_interval; - struct ath_rateset neg_rates; - struct ath_rateset neg_ht_rates; - const struct ath_rate_table *rate_table; - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) - struct dentry *debugfs_rcstats; - struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; -#endif -}; - -#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS) -void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate); -void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, - int xretries, int retries, u8 per); -#else -static inline void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate) -{ -} -static inline void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, - int xretries, int retries, u8 per) -{ -} -#endif - -#ifdef CONFIG_ATH9K_LEGACY_RATE_CONTROL -int ath_rate_control_register(void); -void ath_rate_control_unregister(void); -#else -static inline int ath_rate_control_register(void) -{ - return 0; -} - -static inline void ath_rate_control_unregister(void) -{ -} -#endif - -#endif /* RC_H */ diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 865e043e8aa6..34c74ed99b7b 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -15,11 +15,10 @@ */ #include <linux/dma-mapping.h> -#include <linux/relay.h> #include "ath9k.h" #include "ar9003_mac.h" -#define SKB_CB_ATHBUF(__skb) (*((struct ath_buf **)__skb->cb)) +#define SKB_CB_ATHBUF(__skb) (*((struct ath_rxbuf **)__skb->cb)) static inline bool ath9k_check_auto_sleep(struct ath_softc *sc) { @@ -35,15 +34,14 @@ static inline bool ath9k_check_auto_sleep(struct ath_softc *sc) * buffer (or rx fifo). This can incorrectly acknowledge packets * to a sender if last desc is self-linked. */ -static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) +static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf, + bool flush) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_desc *ds; struct sk_buff *skb; - ATH_RXBUF_RESET(bf); - ds = bf->bf_desc; ds->ds_link = 0; /* link to null */ ds->ds_data = bf->bf_buf_addr; @@ -62,14 +60,23 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) common->rx_bufsize, 0); - if (sc->rx.rxlink == NULL) - ath9k_hw_putrxbuf(ah, bf->bf_daddr); - else + if (sc->rx.rxlink) *sc->rx.rxlink = bf->bf_daddr; + else if (!flush) + ath9k_hw_putrxbuf(ah, bf->bf_daddr); sc->rx.rxlink = &ds->ds_link; } +static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf, + bool flush) +{ + if (sc->rx.buf_hold) + ath_rx_buf_link(sc, sc->rx.buf_hold, flush); + + sc->rx.buf_hold = bf; +} + static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) { /* XXX block beacon interrupts */ @@ -106,18 +113,17 @@ static bool ath_rx_edma_buf_link(struct ath_softc *sc, struct ath_hw *ah = sc->sc_ah; struct ath_rx_edma *rx_edma; struct sk_buff *skb; - struct ath_buf *bf; + struct ath_rxbuf *bf; rx_edma = &sc->rx.rx_edma[qtype]; if (skb_queue_len(&rx_edma->rx_fifo) >= rx_edma->rx_fifo_hwsize) return false; - bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); + bf = list_first_entry(&sc->rx.rxbuf, struct ath_rxbuf, list); list_del_init(&bf->list); skb = bf->bf_mpdu; - ATH_RXBUF_RESET(bf); memset(skb->data, 0, ah->caps.rx_status_len); dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, ah->caps.rx_status_len, DMA_TO_DEVICE); @@ -133,7 +139,7 @@ static void ath_rx_addbuffer_edma(struct ath_softc *sc, enum ath9k_rx_qtype qtype) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_buf *bf, *tbf; + struct ath_rxbuf *bf, *tbf; if (list_empty(&sc->rx.rxbuf)) { ath_dbg(common, QUEUE, "No free rx buf available\n"); @@ -149,7 +155,7 @@ static void ath_rx_addbuffer_edma(struct ath_softc *sc, static void ath_rx_remove_buffer(struct ath_softc *sc, enum ath9k_rx_qtype qtype) { - struct ath_buf *bf; + struct ath_rxbuf *bf; struct ath_rx_edma *rx_edma; struct sk_buff *skb; @@ -166,7 +172,7 @@ static void ath_rx_edma_cleanup(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - struct ath_buf *bf; + struct ath_rxbuf *bf; ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP); ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); @@ -185,7 +191,7 @@ static void ath_rx_edma_cleanup(struct ath_softc *sc) static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size) { - skb_queue_head_init(&rx_edma->rx_fifo); + __skb_queue_head_init(&rx_edma->rx_fifo); rx_edma->rx_fifo_hwsize = size; } @@ -194,7 +200,7 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs) struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_hw *ah = sc->sc_ah; struct sk_buff *skb; - struct ath_buf *bf; + struct ath_rxbuf *bf; int error = 0, i; u32 size; @@ -206,7 +212,7 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs) ath_rx_edma_init_queue(&sc->rx.rx_edma[ATH9K_RX_QUEUE_HP], ah->caps.rx_hp_qdepth); - size = sizeof(struct ath_buf) * nbufs; + size = sizeof(struct ath_rxbuf) * nbufs; bf = devm_kzalloc(sc->dev, size, GFP_KERNEL); if (!bf) return -ENOMEM; @@ -253,7 +259,7 @@ static void ath_edma_start_recv(struct ath_softc *sc) ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP); ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP); ath_opmode_init(sc); - ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)); + ath9k_hw_startpcureceive(sc->sc_ah, sc->cur_chan->offchannel); } static void ath_edma_stop_recv(struct ath_softc *sc) @@ -266,7 +272,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct sk_buff *skb; - struct ath_buf *bf; + struct ath_rxbuf *bf; int error = 0; spin_lock_init(&sc->sc_pcu_lock); @@ -327,7 +333,7 @@ void ath_rx_cleanup(struct ath_softc *sc) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct sk_buff *skb; - struct ath_buf *bf; + struct ath_rxbuf *bf; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { ath_rx_edma_cleanup(sc); @@ -368,8 +374,12 @@ void ath_rx_cleanup(struct ath_softc *sc) u32 ath_calcrxfilter(struct ath_softc *sc) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); u32 rfilt; + if (IS_ENABLED(CONFIG_ATH9K_TX99)) + return 0; + rfilt = ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST | ATH9K_RX_FILTER_MCAST; @@ -377,79 +387,87 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (sc->hw->conf.radar_enabled) rfilt |= ATH9K_RX_FILTER_PHYRADAR | ATH9K_RX_FILTER_PHYERR; - if (sc->rx.rxfilter & FIF_PROBE_REQ) + spin_lock_bh(&sc->chan_lock); + + if (sc->cur_chan->rxfilter & FIF_PROBE_REQ) rfilt |= ATH9K_RX_FILTER_PROBEREQ; - /* - * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station - * mode interface or when in monitor mode. AP mode does not need this - * since it receives all in-BSS frames anyway. - */ if (sc->sc_ah->is_monitoring) rfilt |= ATH9K_RX_FILTER_PROM; - if (sc->rx.rxfilter & FIF_CONTROL) + if ((sc->cur_chan->rxfilter & FIF_CONTROL) || + sc->sc_ah->dynack.enabled) rfilt |= ATH9K_RX_FILTER_CONTROL; if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && - (sc->nvifs <= 1) && - !(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC)) + (sc->cur_chan->nvifs <= 1) && + !(sc->cur_chan->rxfilter & FIF_BCN_PRBRESP_PROMISC)) rfilt |= ATH9K_RX_FILTER_MYBEACON; - else + else if (sc->sc_ah->opmode != NL80211_IFTYPE_OCB) rfilt |= ATH9K_RX_FILTER_BEACON; if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || - (sc->rx.rxfilter & FIF_PSPOLL)) + (sc->cur_chan->rxfilter & FIF_PSPOLL)) rfilt |= ATH9K_RX_FILTER_PSPOLL; - if (conf_is_ht(&sc->hw->conf)) + if (sc->cur_chandef.width != NL80211_CHAN_WIDTH_20_NOHT) rfilt |= ATH9K_RX_FILTER_COMP_BAR; - if (sc->nvifs > 1 || (sc->rx.rxfilter & FIF_OTHER_BSS)) { + if (sc->cur_chan->nvifs > 1 || + (sc->cur_chan->rxfilter & (FIF_OTHER_BSS | FIF_MCAST_ACTION))) { /* This is needed for older chips */ if (sc->sc_ah->hw_version.macVersion <= AR_SREV_VERSION_9160) rfilt |= ATH9K_RX_FILTER_PROM; rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; } - if (AR_SREV_9550(sc->sc_ah)) + if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah) || + AR_SREV_9561(sc->sc_ah)) rfilt |= ATH9K_RX_FILTER_4ADDRESS; + if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah)) + rfilt |= ATH9K_RX_FILTER_CONTROL_WRAPPER; + + if (ath9k_is_chanctx_enabled() && + test_bit(ATH_OP_SCANNING, &common->op_flags)) + rfilt |= ATH9K_RX_FILTER_BEACON; + + spin_unlock_bh(&sc->chan_lock); + return rfilt; } -int ath_startrecv(struct ath_softc *sc) +void ath_startrecv(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - struct ath_buf *bf, *tbf; + struct ath_rxbuf *bf, *tbf; if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { ath_edma_start_recv(sc); - return 0; + return; } if (list_empty(&sc->rx.rxbuf)) goto start_recv; + sc->rx.buf_hold = NULL; sc->rx.rxlink = NULL; list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) { - ath_rx_buf_link(sc, bf); + ath_rx_buf_link(sc, bf, false); } /* We could have deleted elements so the list may be empty now */ if (list_empty(&sc->rx.rxbuf)) goto start_recv; - bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); + bf = list_first_entry(&sc->rx.rxbuf, struct ath_rxbuf, list); ath9k_hw_putrxbuf(ah, bf->bf_daddr); ath9k_hw_rxena(ah); start_recv: ath_opmode_init(sc); - ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)); - - return 0; + ath9k_hw_startpcureceive(ah, sc->cur_chan->offchannel); } static void ath_flushrecv(struct ath_softc *sc) @@ -477,10 +495,9 @@ bool ath_stoprecv(struct ath_softc *sc) if (!(ah->ah_flags & AH_UNPLUGGED) && unlikely(!stopped)) { - ath_err(ath9k_hw_common(sc->sc_ah), - "Could not stop RX, we could be " - "confusing the DMA engine when we start RX up\n"); - ATH_DBG_WARN_ON_ONCE(!stopped); + ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, + "Failed to stop Rx DMA\n"); + RESET_STAT_INC(sc, RESET_RX_DMA_ERROR); } return stopped && !reset; } @@ -520,6 +537,7 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); + bool skip_beacon = false; if (skb->len < 24 + 8 + 2 + 2) return; @@ -530,7 +548,19 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) sc->ps_flags &= ~PS_BEACON_SYNC; ath_dbg(common, PS, "Reconfigure beacon timers based on synchronized timestamp\n"); - ath9k_set_beacon(sc); + +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + if (ath9k_is_chanctx_enabled()) { + if (sc->cur_chan == &sc->offchannel.chan) + skip_beacon = true; + } +#endif + + if (!skip_beacon && + !(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0))) + ath9k_set_beacon(sc); + + ath9k_p2p_beacon_sync(sc); } if (ath_beacon_dtim_pending_cab(skb)) { @@ -597,13 +627,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon) static bool ath_edma_get_buffers(struct ath_softc *sc, enum ath9k_rx_qtype qtype, struct ath_rx_status *rs, - struct ath_buf **dest) + struct ath_rxbuf **dest) { struct ath_rx_edma *rx_edma = &sc->rx.rx_edma[qtype]; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct sk_buff *skb; - struct ath_buf *bf; + struct ath_rxbuf *bf; int ret; skb = skb_peek(&rx_edma->rx_fifo); @@ -647,11 +677,11 @@ static bool ath_edma_get_buffers(struct ath_softc *sc, return true; } -static struct ath_buf *ath_edma_get_next_rx_buf(struct ath_softc *sc, +static struct ath_rxbuf *ath_edma_get_next_rx_buf(struct ath_softc *sc, struct ath_rx_status *rs, enum ath9k_rx_qtype qtype) { - struct ath_buf *bf = NULL; + struct ath_rxbuf *bf = NULL; while (ath_edma_get_buffers(sc, qtype, rs, &bf)) { if (!bf) @@ -662,13 +692,13 @@ static struct ath_buf *ath_edma_get_next_rx_buf(struct ath_softc *sc, return NULL; } -static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, +static struct ath_rxbuf *ath_get_next_rx_buf(struct ath_softc *sc, struct ath_rx_status *rs) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_desc *ds; - struct ath_buf *bf; + struct ath_rxbuf *bf; int ret; if (list_empty(&sc->rx.rxbuf)) { @@ -676,7 +706,10 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, return NULL; } - bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); + bf = list_first_entry(&sc->rx.rxbuf, struct ath_rxbuf, list); + if (bf == sc->rx.buf_hold) + return NULL; + ds = bf->bf_desc; /* @@ -693,7 +726,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, ret = ath9k_hw_rxprocdesc(ah, ds, rs); if (ret == -EINPROGRESS) { struct ath_rx_status trs; - struct ath_buf *tbf; + struct ath_rxbuf *tbf; struct ath_desc *tds; memset(&trs, 0, sizeof(trs)); @@ -702,7 +735,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, return NULL; } - tbf = list_entry(bf->list.next, struct ath_buf, list); + tbf = list_entry(bf->list.next, struct ath_rxbuf, list); /* * On some hardware the descriptor status words could @@ -721,11 +754,18 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, return NULL; /* - * mark descriptor as zero-length and set the 'more' - * flag to ensure that both buffers get discarded + * Re-check previous descriptor, in case it has been filled + * in the mean time. */ - rs->rs_datalen = 0; - rs->rs_more = true; + ret = ath9k_hw_rxprocdesc(ah, ds, rs); + if (ret == -EINPROGRESS) { + /* + * mark descriptor as zero-length and set the 'more' + * flag to ensure that both buffers get discarded + */ + rs->rs_datalen = 0; + rs->rs_more = true; + } } list_del(&bf->list); @@ -744,393 +784,209 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, return bf; } -/* Assumes you've already done the endian to CPU conversion */ -static bool ath9k_rx_accept(struct ath_common *common, - struct ieee80211_hdr *hdr, - struct ieee80211_rx_status *rxs, - struct ath_rx_status *rx_stats, - bool *decrypt_error) +static void ath9k_process_tsf(struct ath_rx_status *rs, + struct ieee80211_rx_status *rxs, + u64 tsf) +{ + u32 tsf_lower = tsf & 0xffffffff; + + rxs->mactime = (tsf & ~0xffffffffULL) | rs->rs_tstamp; + if (rs->rs_tstamp > tsf_lower && + unlikely(rs->rs_tstamp - tsf_lower > 0x10000000)) + rxs->mactime -= 0x100000000ULL; + + if (rs->rs_tstamp < tsf_lower && + unlikely(tsf_lower - rs->rs_tstamp > 0x10000000)) + rxs->mactime += 0x100000000ULL; +} + +/* + * For Decrypt or Demic errors, we only mark packet status here and always push + * up the frame up to let mac80211 handle the actual error case, be it no + * decryption key or real decryption error. This let us keep statistics there. + */ +static int ath9k_rx_skb_preprocess(struct ath_softc *sc, + struct sk_buff *skb, + struct ath_rx_status *rx_stats, + struct ieee80211_rx_status *rx_status, + bool *decrypt_error, u64 tsf) { - struct ath_softc *sc = (struct ath_softc *) common->priv; - bool is_mc, is_valid_tkip, strip_mic, mic_error; - struct ath_hw *ah = common->ah; - __le16 fc; - u8 rx_status_len = ah->caps.rx_status_len; - - fc = hdr->frame_control; - - is_mc = !!is_multicast_ether_addr(hdr->addr1); - is_valid_tkip = rx_stats->rs_keyix != ATH9K_RXKEYIX_INVALID && - test_bit(rx_stats->rs_keyix, common->tkip_keymap); - strip_mic = is_valid_tkip && ieee80211_is_data(fc) && - ieee80211_has_protected(fc) && - !(rx_stats->rs_status & - (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC | - ATH9K_RXERR_KEYMISS)); + struct ieee80211_hw *hw = sc->hw; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_hdr *hdr; + bool discard_current = sc->rx.discard_next; + bool is_phyerr; /* - * Key miss events are only relevant for pairwise keys where the - * descriptor does contain a valid key index. This has been observed - * mostly with CCMP encryption. + * Discard corrupt descriptors which are marked in + * ath_get_next_rx_buf(). */ - if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID || - !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) - rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; + if (discard_current) + goto corrupt; - if (!rx_stats->rs_datalen) { - RX_STAT_INC(rx_len_err); - return false; + sc->rx.discard_next = false; + + /* + * Discard zero-length packets and packets smaller than an ACK + * which are not PHY_ERROR (short radar pulses have a length of 3) + */ + is_phyerr = rx_stats->rs_status & ATH9K_RXERR_PHY; + if (!rx_stats->rs_datalen || + (rx_stats->rs_datalen < 10 && !is_phyerr)) { + RX_STAT_INC(sc, rx_len_err); + goto corrupt; } - /* - * rs_status follows rs_datalen so if rs_datalen is too large - * we can take a hint that hardware corrupted it, so ignore - * those frames. - */ - if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len)) { - RX_STAT_INC(rx_len_err); - return false; + /* + * rs_status follows rs_datalen so if rs_datalen is too large + * we can take a hint that hardware corrupted it, so ignore + * those frames. + */ + if (rx_stats->rs_datalen > (common->rx_bufsize - ah->caps.rx_status_len)) { + RX_STAT_INC(sc, rx_len_err); + goto corrupt; } - /* Only use error bits from the last fragment */ + /* Only use status info from the last fragment */ if (rx_stats->rs_more) - return true; - - mic_error = is_valid_tkip && !ieee80211_is_ctl(fc) && - !ieee80211_has_morefrags(fc) && - !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && - (rx_stats->rs_status & ATH9K_RXERR_MIC); + return 0; /* - * The rx_stats->rs_status will not be set until the end of the - * chained descriptors so it can be ignored if rs_more is set. The - * rs_more will be false at the last element of the chained - * descriptors. + * Return immediately if the RX descriptor has been marked + * as corrupt based on the various error bits. + * + * This is different from the other corrupt descriptor + * condition handled above. */ - if (rx_stats->rs_status != 0) { - u8 status_mask; + if (rx_stats->rs_status & ATH9K_RXERR_CORRUPT_DESC) + goto corrupt; - if (rx_stats->rs_status & ATH9K_RXERR_CRC) { - rxs->flag |= RX_FLAG_FAILED_FCS_CRC; - mic_error = false; - } - if (rx_stats->rs_status & ATH9K_RXERR_PHY) - return false; + hdr = (struct ieee80211_hdr *) (skb->data + ah->caps.rx_status_len); - if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) || - (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) { - *decrypt_error = true; - mic_error = false; - } + ath9k_process_tsf(rx_stats, rx_status, tsf); + ath_debug_stat_rx(sc, rx_stats); + /* + * Process PHY errors and return so that the packet + * can be dropped. + */ + if (rx_stats->rs_status & ATH9K_RXERR_PHY) { /* - * Reject error frames with the exception of - * decryption and MIC failures. For monitor mode, - * we also ignore the CRC error. + * DFS and spectral are mutually exclusive + * + * Since some chips use PHYERR_RADAR as indication for both, we + * need to double check which feature is enabled to prevent + * feeding spectral or dfs-detector with wrong frames. */ - status_mask = ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | - ATH9K_RXERR_KEYMISS; - - if (ah->is_monitoring && (sc->rx.rxfilter & FIF_FCSFAIL)) - status_mask |= ATH9K_RXERR_CRC; - - if (rx_stats->rs_status & ~status_mask) - return false; + if (hw->conf.radar_enabled) { + ath9k_dfs_process_phyerr(sc, hdr, rx_stats, + rx_status->mactime); + } else if (sc->spec_priv.spectral_mode != SPECTRAL_DISABLED && + ath_cmn_process_fft(&sc->spec_priv, hdr, rx_stats, + rx_status->mactime)) { + RX_STAT_INC(sc, rx_spectral); + } + return -EINVAL; } /* - * For unicast frames the MIC error bit can have false positives, - * so all MIC error reports need to be validated in software. - * False negatives are not common, so skip software verification - * if the hardware considers the MIC valid. + * everything but the rate is checked here, the rate check is done + * separately to avoid doing two lookups for a rate for each frame. */ - if (strip_mic) - rxs->flag |= RX_FLAG_MMIC_STRIPPED; - else if (is_mc && mic_error) - rxs->flag |= RX_FLAG_MMIC_ERROR; - - return true; -} - -static int ath9k_process_rate(struct ath_common *common, - struct ieee80211_hw *hw, - struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rxs) -{ - struct ieee80211_supported_band *sband; - enum ieee80211_band band; - unsigned int i = 0; - struct ath_softc __maybe_unused *sc = common->priv; - - band = hw->conf.chandef.chan->band; - sband = hw->wiphy->bands[band]; - - if (rx_stats->rs_rate & 0x80) { - /* HT rate */ - rxs->flag |= RX_FLAG_HT; - rxs->flag |= rx_stats->flag; - rxs->rate_idx = rx_stats->rs_rate & 0x7f; - return 0; + spin_lock_bh(&sc->chan_lock); + if (!ath9k_cmn_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error, + sc->cur_chan->rxfilter)) { + spin_unlock_bh(&sc->chan_lock); + return -EINVAL; } + spin_unlock_bh(&sc->chan_lock); - for (i = 0; i < sband->n_bitrates; i++) { - if (sband->bitrates[i].hw_value == rx_stats->rs_rate) { - rxs->rate_idx = i; - return 0; - } - if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { - rxs->flag |= RX_FLAG_SHORTPRE; - rxs->rate_idx = i; - return 0; - } + if (ath_is_mybeacon(common, hdr)) { + RX_STAT_INC(sc, rx_beacons); + rx_stats->is_mybeacon = true; } /* - * No valid hardware bitrate found -- we should not get here - * because hardware has already validated this frame as OK. + * This shouldn't happen, but have a safety check anyway. */ - ath_dbg(common, ANY, - "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", - rx_stats->rs_rate); - RX_STAT_INC(rx_rate_err); - return -EINVAL; -} - -static void ath9k_process_rssi(struct ath_common *common, - struct ieee80211_hw *hw, - struct ieee80211_hdr *hdr, - struct ath_rx_status *rx_stats) -{ - struct ath_softc *sc = hw->priv; - struct ath_hw *ah = common->ah; - int last_rssi; - int rssi = rx_stats->rs_rssi; - - if (!rx_stats->is_mybeacon || - ((ah->opmode != NL80211_IFTYPE_STATION) && - (ah->opmode != NL80211_IFTYPE_ADHOC))) - return; - - if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr) - ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi); - - last_rssi = sc->last_rssi; - if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) - rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); - if (rssi < 0) - rssi = 0; - - /* Update Beacon RSSI, this is used by ANI. */ - ah->stats.avgbrssi = rssi; -} - -/* - * For Decrypt or Demic errors, we only mark packet status here and always push - * up the frame up to let mac80211 handle the actual error case, be it no - * decryption key or real decryption error. This let us keep statistics there. - */ -static int ath9k_rx_skb_preprocess(struct ath_softc *sc, - struct ieee80211_hdr *hdr, - struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rx_status, - bool *decrypt_error) -{ - struct ieee80211_hw *hw = sc->hw; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - bool discard_current = sc->rx.discard_next; - - sc->rx.discard_next = rx_stats->rs_more; - if (discard_current) + if (WARN_ON(!ah->curchan)) return -EINVAL; - /* - * everything but the rate is checked here, the rate check is done - * separately to avoid doing two lookups for a rate for each frame. - */ - if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) + if (ath9k_cmn_process_rate(common, hw, rx_stats, rx_status)) { + /* + * No valid hardware bitrate found -- we should not get here + * because hardware has already validated this frame as OK. + */ + ath_dbg(common, ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", + rx_stats->rs_rate); + RX_STAT_INC(sc, rx_rate_err); return -EINVAL; + } - /* Only use status info from the last fragment */ - if (rx_stats->rs_more) - return 0; - - if (ath9k_process_rate(common, hw, rx_stats, rx_status)) - return -EINVAL; + if (ath9k_is_chanctx_enabled()) { + if (rx_stats->is_mybeacon) + ath_chanctx_beacon_recv_ev(sc, + ATH_CHANCTX_EVENT_BEACON_RECEIVED); + } - ath9k_process_rssi(common, hw, hdr, rx_stats); + ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status); - rx_status->band = hw->conf.chandef.chan->band; - rx_status->freq = hw->conf.chandef.chan->center_freq; - rx_status->signal = ah->noise + rx_stats->rs_rssi; + rx_status->band = ah->curchan->chan->band; + rx_status->freq = ah->curchan->chan->center_freq; rx_status->antenna = rx_stats->rs_antenna; rx_status->flag |= RX_FLAG_MACTIME_END; - if (rx_stats->rs_moreaggr) - rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; - - sc->rx.discard_next = false; - return 0; -} - -static void ath9k_rx_skb_postprocess(struct ath_common *common, - struct sk_buff *skb, - struct ath_rx_status *rx_stats, - struct ieee80211_rx_status *rxs, - bool decrypt_error) -{ - struct ath_hw *ah = common->ah; - struct ieee80211_hdr *hdr; - int hdrlen, padpos, padsize; - u8 keyix; - __le16 fc; - - /* see if any padding is done by the hw and remove it */ - hdr = (struct ieee80211_hdr *) skb->data; - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - fc = hdr->frame_control; - padpos = ieee80211_hdrlen(fc); - - /* The MAC header is padded to have 32-bit boundary if the - * packet payload is non-zero. The general calculation for - * padsize would take into account odd header lengths: - * padsize = (4 - padpos % 4) % 4; However, since only - * even-length headers are used, padding can only be 0 or 2 - * bytes and we can optimize this a bit. In addition, we must - * not try to remove padding from short control frames that do - * not have payload. */ - padsize = padpos & 3; - if (padsize && skb->len>=padpos+padsize+FCS_LEN) { - memmove(skb->data + padsize, skb->data, padpos); - skb_pull(skb, padsize); - } - keyix = rx_stats->rs_keyix; - - if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error && - ieee80211_has_protected(fc)) { - rxs->flag |= RX_FLAG_DECRYPTED; - } else if (ieee80211_has_protected(fc) - && !decrypt_error && skb->len >= hdrlen + 4) { - keyix = skb->data[hdrlen + 3] >> 6; +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + if (ieee80211_is_data_present(hdr->frame_control) && + !ieee80211_is_qos_nullfunc(hdr->frame_control)) + sc->rx.num_pkts++; +#endif - if (test_bit(keyix, common->keymap)) - rxs->flag |= RX_FLAG_DECRYPTED; - } - if (ah->sw_mgmt_crypto && - (rxs->flag & RX_FLAG_DECRYPTED) && - ieee80211_is_mgmt(fc)) - /* Use software decrypt for management frames. */ - rxs->flag &= ~RX_FLAG_DECRYPTED; -} + return 0; -#ifdef CONFIG_ATH9K_DEBUGFS -static s8 fix_rssi_inv_only(u8 rssi_val) -{ - if (rssi_val == 128) - rssi_val = 0; - return (s8) rssi_val; +corrupt: + sc->rx.discard_next = rx_stats->rs_more; + return -EINVAL; } -#endif -/* returns 1 if this was a spectral frame, even if not handled. */ -static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, - struct ath_rx_status *rs, u64 tsf) +/* + * Run the LNA combining algorithm only in these cases: + * + * Standalone WLAN cards with both LNA/Antenna diversity + * enabled in the EEPROM. + * + * WLAN+BT cards which are in the supported card list + * in ath_pci_id_table and the user has loaded the + * driver with "bt_ant_diversity" set to true. + */ +static void ath9k_antenna_check(struct ath_softc *sc, + struct ath_rx_status *rs) { -#ifdef CONFIG_ATH9K_DEBUGFS struct ath_hw *ah = sc->sc_ah; - u8 bins[SPECTRAL_HT20_NUM_BINS]; - u8 *vdata = (u8 *)hdr; - struct fft_sample_ht20 fft_sample; - struct ath_radar_info *radar_info; - struct ath_ht20_mag_info *mag_info; - int len = rs->rs_datalen; - int dc_pos; - u16 length, max_magnitude; - - /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer - * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT - * yet, but this is supposed to be possible as well. - */ - if (rs->rs_phyerr != ATH9K_PHYERR_RADAR && - rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT && - rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) - return 0; + struct ath9k_hw_capabilities *pCap = &ah->caps; + struct ath_common *common = ath9k_hw_common(ah); - /* check if spectral scan bit is set. This does not have to be checked - * if received through a SPECTRAL phy error, but shouldn't hurt. - */ - radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; - if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) - return 0; + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)) + return; - /* Variation in the data length is possible and will be fixed later. - * Note that we only support HT20 for now. - * - * TODO: add HT20_40 support as well. + /* + * Change the default rx antenna if rx diversity + * chooses the other antenna 3 times in a row. */ - if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) || - (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1)) - return 1; - - fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20; - length = sizeof(fft_sample) - sizeof(fft_sample.tlv); - fft_sample.tlv.length = __cpu_to_be16(length); - - fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq); - fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0); - fft_sample.noise = ah->noise; - - switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) { - case 0: - /* length correct, nothing to do. */ - memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS); - break; - case -1: - /* first byte missing, duplicate it. */ - memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1); - bins[0] = vdata[0]; - break; - case 2: - /* MAC added 2 extra bytes at bin 30 and 32, remove them. */ - memcpy(bins, vdata, 30); - bins[30] = vdata[31]; - memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31); - break; - case 1: - /* MAC added 2 extra bytes AND first byte is missing. */ - bins[0] = vdata[0]; - memcpy(&bins[0], vdata, 30); - bins[31] = vdata[31]; - memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32); - break; - default: - return 1; + if (sc->rx.defant != rs->rs_antenna) { + if (++sc->rx.rxotherant >= 3) + ath_setdefantenna(sc, rs->rs_antenna); + } else { + sc->rx.rxotherant = 0; } - /* DC value (value in the middle) is the blind spot of the spectral - * sample and invalid, interpolate it. - */ - dc_pos = SPECTRAL_HT20_NUM_BINS / 2; - bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2; - - /* mag data is at the end of the frame, in front of radar_info */ - mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1; - - /* copy raw bins without scaling them */ - memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS); - fft_sample.max_exp = mag_info->max_exp & 0xf; - - max_magnitude = spectral_max_magnitude(mag_info->all_bins); - fft_sample.max_magnitude = __cpu_to_be16(max_magnitude); - fft_sample.max_index = spectral_max_index(mag_info->all_bins); - fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins); - fft_sample.tsf = __cpu_to_be64(tsf); - - ath_debug_send_fft_sample(sc, &fft_sample.tlv); - return 1; -#else - return 0; -#endif + if (pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV) { + if (common->bt_ant_diversity) + ath_ant_comb_scan(sc, rs); + } else { + ath_ant_comb_scan(sc, rs); + } } static void ath9k_apply_ampdu_details(struct ath_softc *sc, @@ -1151,25 +1007,74 @@ static void ath9k_apply_ampdu_details(struct ath_softc *sc, } } +static void ath_rx_count_airtime(struct ath_softc *sc, + struct ath_rx_status *rs, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_sta *sta; + struct ieee80211_rx_status *rxs; + const struct ieee80211_rate *rate; + bool is_sgi, is_40, is_sp; + int phy; + u16 len = rs->rs_datalen; + u32 airtime = 0; + u8 tidno; + + if (!ieee80211_is_data(hdr->frame_control)) + return; + + rcu_read_lock(); + + sta = ieee80211_find_sta_by_ifaddr(sc->hw, hdr->addr2, NULL); + if (!sta) + goto exit; + tidno = skb->priority & IEEE80211_QOS_CTL_TID_MASK; + + rxs = IEEE80211_SKB_RXCB(skb); + + is_sgi = !!(rxs->enc_flags & RX_ENC_FLAG_SHORT_GI); + is_40 = !!(rxs->bw == RATE_INFO_BW_40); + is_sp = !!(rxs->enc_flags & RX_ENC_FLAG_SHORTPRE); + + if (!!(rxs->encoding == RX_ENC_HT)) { + /* MCS rates */ + + airtime += ath_pkt_duration(rxs->rate_idx, len, + is_40, is_sgi, is_sp); + } else { + + phy = IS_CCK_RATE(rs->rs_rate) ? WLAN_RC_PHY_CCK : WLAN_RC_PHY_OFDM; + rate = &common->sbands[rxs->band].bitrates[rxs->rate_idx]; + airtime += ath9k_hw_computetxtime(ah, phy, rate->bitrate * 100, + len, rxs->rate_idx, is_sp); + } + + ieee80211_sta_register_airtime(sta, tidno, 0, airtime); +exit: + rcu_read_unlock(); +} + int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) { - struct ath_buf *bf; + struct ath_rxbuf *bf; struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb; struct ieee80211_rx_status *rxs; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_hw *hw = sc->hw; - struct ieee80211_hdr *hdr; int retval; struct ath_rx_status rs; enum ath9k_rx_qtype qtype; bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); int dma_type; - u8 rx_status_len = ah->caps.rx_status_len; u64 tsf = 0; - u32 tsf_lower = 0; unsigned long flags; dma_addr_t new_buf_addr; + unsigned int budget = 512; + struct ieee80211_hdr *hdr; if (edma) dma_type = DMA_BIDIRECTIONAL; @@ -1179,7 +1084,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP; tsf = ath9k_hw_gettsf64(ah); - tsf_lower = tsf & 0xffffffff; do { bool decrypt_error = false; @@ -1206,55 +1110,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) else hdr_skb = skb; - hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len); rxs = IEEE80211_SKB_RXCB(hdr_skb); - if (ieee80211_is_beacon(hdr->frame_control)) { - RX_STAT_INC(rx_beacons); - if (!is_zero_ether_addr(common->curbssid) && - ether_addr_equal(hdr->addr3, common->curbssid)) - rs.is_mybeacon = true; - else - rs.is_mybeacon = false; - } - else - rs.is_mybeacon = false; - - if (ieee80211_is_data_present(hdr->frame_control) && - !ieee80211_is_qos_nullfunc(hdr->frame_control)) - sc->rx.num_pkts++; - - ath_debug_stat_rx(sc, &rs); - memset(rxs, 0, sizeof(struct ieee80211_rx_status)); - rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; - if (rs.rs_tstamp > tsf_lower && - unlikely(rs.rs_tstamp - tsf_lower > 0x10000000)) - rxs->mactime -= 0x100000000ULL; - - if (rs.rs_tstamp < tsf_lower && - unlikely(tsf_lower - rs.rs_tstamp > 0x10000000)) - rxs->mactime += 0x100000000ULL; - - if (rs.rs_phyerr == ATH9K_PHYERR_RADAR) - ath9k_dfs_process_phyerr(sc, hdr, &rs, rxs->mactime); - - if (rs.rs_status & ATH9K_RXERR_PHY) { - if (ath_process_fft(sc, hdr, &rs, rxs->mactime)) { - RX_STAT_INC(rx_spectral); - goto requeue_drop_frag; - } - } - - retval = ath9k_rx_skb_preprocess(sc, hdr, &rs, rxs, - &decrypt_error); + retval = ath9k_rx_skb_preprocess(sc, hdr_skb, &rs, rxs, + &decrypt_error, tsf); if (retval) goto requeue_drop_frag; - if (rs.is_mybeacon) { - sc->hw_busy_count = 0; - ath_start_rx_poll(sc, 3); - } /* Ensure we always have an skb to requeue once we are done * processing the current buffer's skb */ requeue_skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_ATOMIC); @@ -1264,7 +1127,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) * skb and put it at the tail of the sc->rx.rxbuf list for * processing. */ if (!requeue_skb) { - RX_STAT_INC(rx_oom_err); + RX_STAT_INC(sc, rx_oom_err); goto requeue_drop_frag; } @@ -1288,11 +1151,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) skb_pull(skb, ah->caps.rx_status_len); if (!rs.rs_more) - ath9k_rx_skb_postprocess(common, hdr_skb, &rs, - rxs, decrypt_error); + ath9k_cmn_rx_skb_postprocess(common, hdr_skb, &rs, + rxs, decrypt_error); if (rs.rs_more) { - RX_STAT_INC(rx_frags); + RX_STAT_INC(sc, rx_frags); /* * rs_more indicates chained descriptors which can be * used to link buffers together for a sort of @@ -1302,21 +1165,19 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) /* too many fragments - cannot handle frame */ dev_kfree_skb_any(sc->rx.frag); dev_kfree_skb_any(skb); - RX_STAT_INC(rx_too_many_frags_err); + RX_STAT_INC(sc, rx_too_many_frags_err); skb = NULL; } sc->rx.frag = skb; goto requeue; } - if (rs.rs_status & ATH9K_RXERR_CORRUPT_DESC) - goto requeue_drop_frag; if (sc->rx.frag) { int space = skb->len - skb_tailroom(hdr_skb); if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) { dev_kfree_skb(skb); - RX_STAT_INC(rx_oom_err); + RX_STAT_INC(sc, rx_oom_err); goto requeue_drop_frag; } @@ -1328,22 +1189,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) skb = hdr_skb; } - - if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) { - - /* - * change the default rx antenna if rx diversity - * chooses the other antenna 3 times in a row. - */ - if (sc->rx.defant != rs.rs_antenna) { - if (++sc->rx.rxotherant >= 3) - ath_setdefantenna(sc, rs.rs_antenna); - } else { - sc->rx.rxotherant = 0; - } - - } - if (rxs->flag & RX_FLAG_MMIC_STRIPPED) skb_trim(skb, skb->len - 8); @@ -1355,10 +1200,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) ath_rx_ps(sc, skb, rs.is_mybeacon); spin_unlock_irqrestore(&sc->sc_pm_lock, flags); - if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3) - ath_ant_comb_scan(sc, &rs); - + ath9k_antenna_check(sc, &rs); ath9k_apply_ampdu_details(sc, &rs, rxs); + ath_debug_rate_stats(sc, &rs, skb); + ath_rx_count_airtime(sc, &rs, skb); + + hdr = (struct ieee80211_hdr *)skb->data; + if (ieee80211_is_ack(hdr->frame_control)) + ath_dynack_sample_ack_ts(sc->sc_ah, skb, rs.rs_tstamp); ieee80211_rx(hw, skb); @@ -1369,15 +1218,17 @@ requeue_drop_frag: } requeue: list_add_tail(&bf->list, &sc->rx.rxbuf); - if (flush) - continue; - if (edma) { + if (!edma) { + ath_rx_buf_relink(sc, bf, flush); + if (!flush) + ath9k_hw_rxena(ah); + } else if (!flush) { ath_rx_edma_buf_link(sc, qtype); - } else { - ath_rx_buf_link(sc, bf); - ath9k_hw_rxena(ah); } + + if (!budget--) + break; } while (1); if (!(ah->imask & ATH9K_INT_RXEOL)) { diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 5af97442ac37..9f5b8a538071 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -20,7 +20,7 @@ #include "../reg.h" #define AR_CR 0x0008 -#define AR_CR_RXE (AR_SREV_9300_20_OR_LATER(ah) ? 0x0000000c : 0x00000004) +#define AR_CR_RXE(_ah) (AR_SREV_9300_20_OR_LATER(_ah) ? 0x0000000c : 0x00000004) #define AR_CR_RXD 0x00000020 #define AR_CR_SWI 0x00000040 @@ -34,8 +34,10 @@ #define AR_CFG_SWRG 0x00000010 #define AR_CFG_AP_ADHOC_INDICATION 0x00000020 #define AR_CFG_PHOK 0x00000100 -#define AR_CFG_CLK_GATE_DIS 0x00000400 #define AR_CFG_EEBS 0x00000200 +#define AR_CFG_CLK_GATE_DIS 0x00000400 +#define AR_CFG_HALT_REQ 0x00000800 +#define AR_CFG_HALT_ACK 0x00001000 #define AR_CFG_PCI_MASTER_REQ_Q_THRESH 0x00060000 #define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S 17 @@ -144,6 +146,14 @@ #define AR_MACMISC_MISC_OBS_BUS_MSB_S 15 #define AR_MACMISC_MISC_OBS_BUS_1 1 +#define AR_INTCFG 0x005C +#define AR_INTCFG_MSI_RXOK 0x00000000 +#define AR_INTCFG_MSI_RXINTM 0x00000004 +#define AR_INTCFG_MSI_RXMINTR 0x00000006 +#define AR_INTCFG_MSI_TXOK 0x00000000 +#define AR_INTCFG_MSI_TXINTM 0x00000010 +#define AR_INTCFG_MSI_TXMINTR 0x00000018 + #define AR_DATABUF_SIZE 0x0060 #define AR_DATABUF_SIZE_MASK 0x00000FFF @@ -304,6 +314,7 @@ #define AR_IMR_S2 0x00ac #define AR_IMR_S2_QCU_TXURN 0x000003FF #define AR_IMR_S2_QCU_TXURN_S 0 +#define AR_IMR_S2_BB_WATCHDOG 0x00010000 #define AR_IMR_S2_CST 0x00400000 #define AR_IMR_S2_GTT 0x00800000 #define AR_IMR_S2_TIM 0x01000000 @@ -341,10 +352,10 @@ #define AR_ISR_S1_QCU_TXEOL 0x03FF0000 #define AR_ISR_S1_QCU_TXEOL_S 16 -#define AR_ISR_S2_S (AR_SREV_9300_20_OR_LATER(ah) ? 0x00d0 : 0x00cc) -#define AR_ISR_S3_S (AR_SREV_9300_20_OR_LATER(ah) ? 0x00d4 : 0x00d0) -#define AR_ISR_S4_S (AR_SREV_9300_20_OR_LATER(ah) ? 0x00d8 : 0x00d4) -#define AR_ISR_S5_S (AR_SREV_9300_20_OR_LATER(ah) ? 0x00dc : 0x00d8) +#define AR_ISR_S2_S(_ah) (AR_SREV_9300_20_OR_LATER(_ah) ? 0x00d0 : 0x00cc) +#define AR_ISR_S3_S(_ah) (AR_SREV_9300_20_OR_LATER(_ah) ? 0x00d4 : 0x00d0) +#define AR_ISR_S4_S(_ah) (AR_SREV_9300_20_OR_LATER(_ah) ? 0x00d8 : 0x00d4) +#define AR_ISR_S5_S(_ah) (AR_SREV_9300_20_OR_LATER(_ah) ? 0x00dc : 0x00d8) #define AR_DMADBG_0 0x00e0 #define AR_DMADBG_1 0x00e4 #define AR_DMADBG_2 0x00e8 @@ -504,9 +515,6 @@ #define AR_D_QCUMASK 0x000003FF #define AR_D_QCUMASK_RESV0 0xFFFFFC00 -#define AR_D_TXBLK_CMD 0x1038 -#define AR_D_TXBLK_DATA(i) (AR_D_TXBLK_CMD+(i)) - #define AR_D0_LCL_IFS 0x1040 #define AR_D1_LCL_IFS 0x1044 #define AR_D2_LCL_IFS 0x1048 @@ -691,7 +699,7 @@ #define AR_RC_APB 0x00000002 #define AR_RC_HOSTIF 0x00000100 -#define AR_WA (AR_SREV_9340(ah) ? 0x40c4 : 0x4004) +#define AR_WA(_ah) (AR_SREV_9340(_ah) ? 0x40c4 : 0x4004) #define AR_WA_BIT6 (1 << 6) #define AR_WA_BIT7 (1 << 7) #define AR_WA_BIT23 (1 << 23) @@ -713,7 +721,7 @@ #define AR_PM_STATE 0x4008 #define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000 -#define AR_HOST_TIMEOUT (AR_SREV_9340(ah) ? 0x4008 : 0x4018) +#define AR_HOST_TIMEOUT(_ah) (AR_SREV_9340(_ah) ? 0x4008 : 0x4018) #define AR_HOST_TIMEOUT_APB_CNTR 0x0000FFFF #define AR_HOST_TIMEOUT_APB_CNTR_S 0 #define AR_HOST_TIMEOUT_LCL_CNTR 0xFFFF0000 @@ -742,12 +750,12 @@ #define EEPROM_PROTECT_RP_1024_2047 0x4000 #define EEPROM_PROTECT_WP_1024_2047 0x8000 -#define AR_SREV \ - ((AR_SREV_9100(ah)) ? 0x0600 : (AR_SREV_9340(ah) \ +#define AR_SREV(_ah) \ + ((AR_SREV_9100(_ah)) ? 0x0600 : (AR_SREV_9340(_ah) \ ? 0x400c : 0x4020)) -#define AR_SREV_ID \ - ((AR_SREV_9100(ah)) ? 0x00000FFF : 0x000000FF) +#define AR_SREV_ID(_ah) \ + ((AR_SREV_9100(_ah)) ? 0x00000FFF : 0x000000FF) #define AR_SREV_VERSION 0x000000F0 #define AR_SREV_VERSION_S 4 #define AR_SREV_REVISION 0x00000007 @@ -809,7 +817,14 @@ #define AR_SREV_REVISION_9462_21 3 #define AR_SREV_VERSION_9565 0x2C0 #define AR_SREV_REVISION_9565_10 0 +#define AR_SREV_REVISION_9565_101 1 +#define AR_SREV_REVISION_9565_11 2 #define AR_SREV_VERSION_9550 0x400 +#define AR_SREV_VERSION_9531 0x500 +#define AR_SREV_REVISION_9531_10 0 +#define AR_SREV_REVISION_9531_11 1 +#define AR_SREV_REVISION_9531_20 2 +#define AR_SREV_VERSION_9561 0x600 #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -819,8 +834,8 @@ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_22)) || \ ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100)) -#define AR_SREV_9100(ah) \ - ((ah->hw_version.macVersion) == AR_SREV_VERSION_9100) +#define AR_SREV_9100(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9100)) #define AR_SREV_9100_OR_LATER(_ah) \ (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100)) @@ -876,14 +891,11 @@ #define AR_SREV_9300_20_OR_LATER(_ah) \ ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300) #define AR_SREV_9300_22(_ah) \ - (AR_SREV_9300(ah) && \ + (AR_SREV_9300((_ah)) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9300_22)) #define AR_SREV_9330(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9330)) -#define AR_SREV_9330_10(_ah) \ - (AR_SREV_9330((_ah)) && \ - ((_ah)->hw_version.macRev == AR_SREV_REVISION_9330_10)) #define AR_SREV_9330_11(_ah) \ (AR_SREV_9330((_ah)) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9330_11)) @@ -891,17 +903,35 @@ (AR_SREV_9330((_ah)) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9330_12)) +#ifdef CONFIG_ATH9K_PCOEM +#define AR_SREV_9462(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462)) #define AR_SREV_9485(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485)) -#define AR_SREV_9485_11(_ah) \ +#define AR_SREV_9565(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565)) +#define AR_SREV_9003_PCOEM(_ah) \ + (AR_SREV_9462(_ah) || AR_SREV_9485(_ah) || AR_SREV_9565(_ah)) +#else +#define AR_SREV_9462(_ah) 0 +#define AR_SREV_9485(_ah) 0 +#define AR_SREV_9565(_ah) 0 +#define AR_SREV_9003_PCOEM(_ah) 0 +#endif + +#define AR_SREV_9485_11_OR_LATER(_ah) \ (AR_SREV_9485(_ah) && \ - ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11)) + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9485_11)) #define AR_SREV_9485_OR_LATER(_ah) \ (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485)) #define AR_SREV_9340(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340)) +#define AR_SREV_9340_13(_ah) \ + (AR_SREV_9340((_ah)) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9340_13)) + #define AR_SREV_9340_13_OR_LATER(_ah) \ (AR_SREV_9340((_ah)) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9340_13)) @@ -910,39 +940,63 @@ (AR_SREV_9285_12_OR_LATER(_ah) && \ ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1)) -#define AR_SREV_9462(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462)) #define AR_SREV_9462_20(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ + (AR_SREV_9462(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_20)) #define AR_SREV_9462_21(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ + (AR_SREV_9462(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_21)) #define AR_SREV_9462_20_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ + (AR_SREV_9462(_ah) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_20)) #define AR_SREV_9462_21_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ + (AR_SREV_9462(_ah) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_21)) -#define AR_SREV_9565(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565)) - #define AR_SREV_9565_10(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \ + (AR_SREV_9565(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_10)) +#define AR_SREV_9565_101(_ah) \ + (AR_SREV_9565(_ah) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_101)) +#define AR_SREV_9565_11(_ah) \ + (AR_SREV_9565(_ah) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_11)) +#define AR_SREV_9565_11_OR_LATER(_ah) \ + (AR_SREV_9565(_ah) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9565_11)) #define AR_SREV_9550(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9550)) +#define AR_SREV_9550_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9550)) #define AR_SREV_9580(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9580_10)) - #define AR_SREV_9580_10(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9580_10)) +#define AR_SREV_9531(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531)) +#define AR_SREV_9531_10(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_10)) +#define AR_SREV_9531_11(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_11)) +#define AR_SREV_9531_20(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_20)) + +#define AR_SREV_9561(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9561)) + +#define AR_SREV_SOC(_ah) \ + (AR_SREV_9340(_ah) || AR_SREV_9531(_ah) || AR_SREV_9550(_ah) || \ + AR_SREV_9561(_ah)) + /* NOTE: When adding chips newer than Peacock, add chip check here */ #define AR_SREV_9580_10_OR_LATER(_ah) \ (AR_SREV_9580(_ah)) @@ -984,11 +1038,11 @@ enum ath_usb_dev { #define AR_INTR_SPURIOUS 0xFFFFFFFF -#define AR_INTR_SYNC_CAUSE (AR_SREV_9340(ah) ? 0x4010 : 0x4028) -#define AR_INTR_SYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4010 : 0x4028) +#define AR_INTR_SYNC_CAUSE(_ah) (AR_SREV_9340(_ah) ? 0x4010 : 0x4028) +#define AR_INTR_SYNC_CAUSE_CLR(_ah) (AR_SREV_9340(_ah) ? 0x4010 : 0x4028) -#define AR_INTR_SYNC_ENABLE (AR_SREV_9340(ah) ? 0x4014 : 0x402c) +#define AR_INTR_SYNC_ENABLE(_ah) (AR_SREV_9340(_ah) ? 0x4014 : 0x402c) #define AR_INTR_SYNC_ENABLE_GPIO 0xFFFC0000 #define AR_INTR_SYNC_ENABLE_GPIO_S 18 @@ -1030,18 +1084,18 @@ enum { }; -#define AR_INTR_ASYNC_MASK (AR_SREV_9340(ah) ? 0x4018 : 0x4030) +#define AR_INTR_ASYNC_MASK(_ah) (AR_SREV_9340(_ah) ? 0x4018 : 0x4030) #define AR_INTR_ASYNC_MASK_GPIO 0xFFFC0000 #define AR_INTR_ASYNC_MASK_GPIO_S 18 #define AR_INTR_ASYNC_MASK_MCI 0x00000080 #define AR_INTR_ASYNC_MASK_MCI_S 7 -#define AR_INTR_SYNC_MASK (AR_SREV_9340(ah) ? 0x401c : 0x4034) +#define AR_INTR_SYNC_MASK(_ah) (AR_SREV_9340(_ah) ? 0x401c : 0x4034) #define AR_INTR_SYNC_MASK_GPIO 0xFFFC0000 #define AR_INTR_SYNC_MASK_GPIO_S 18 -#define AR_INTR_ASYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4020 : 0x4038) -#define AR_INTR_ASYNC_CAUSE (AR_SREV_9340(ah) ? 0x4020 : 0x4038) +#define AR_INTR_ASYNC_CAUSE_CLR(_ah) (AR_SREV_9340(_ah) ? 0x4020 : 0x4038) +#define AR_INTR_ASYNC_CAUSE(_ah) (AR_SREV_9340(_ah) ? 0x4020 : 0x4038) #define AR_INTR_ASYNC_CAUSE_MCI 0x00000080 #define AR_INTR_ASYNC_USED (AR_INTR_MAC_IRQ | \ AR_INTR_ASYNC_CAUSE_MCI) @@ -1051,26 +1105,58 @@ enum { #define AR_INTR_ASYNC_ENABLE_MCI_S 7 -#define AR_INTR_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4024 : 0x403c) +#define AR_INTR_ASYNC_ENABLE(_ah) (AR_SREV_9340(_ah) ? 0x4024 : 0x403c) #define AR_INTR_ASYNC_ENABLE_GPIO 0xFFFC0000 #define AR_INTR_ASYNC_ENABLE_GPIO_S 18 #define AR_PCIE_SERDES 0x4040 #define AR_PCIE_SERDES2 0x4044 -#define AR_PCIE_PM_CTRL (AR_SREV_9340(ah) ? 0x4004 : 0x4014) +#define AR_PCIE_PM_CTRL(_ah) (AR_SREV_9340(_ah) ? 0x4004 : 0x4014) #define AR_PCIE_PM_CTRL_ENA 0x00080000 #define AR_PCIE_PHY_REG3 0x18c08 +/* Define correct GPIO numbers and MASK bits to indicate the WMAC + * GPIO resource. + * Allow SOC chips(AR9340, AR9531, AR9550, AR9561) to access all GPIOs + * which rely on gpiolib framework. But restrict SOC AR9330 only to + * access WMAC GPIO which has the same design with the old chips. + */ #define AR_NUM_GPIO 14 -#define AR928X_NUM_GPIO 10 +#define AR9280_NUM_GPIO 10 #define AR9285_NUM_GPIO 12 -#define AR9287_NUM_GPIO 11 +#define AR9287_NUM_GPIO 10 #define AR9271_NUM_GPIO 16 -#define AR9300_NUM_GPIO 17 +#define AR9300_NUM_GPIO 16 +#define AR9330_NUM_GPIO 16 +#define AR9340_NUM_GPIO 23 +#define AR9462_NUM_GPIO 14 +#define AR9485_NUM_GPIO 12 +#define AR9531_NUM_GPIO 18 +#define AR9550_NUM_GPIO 24 +#define AR9561_NUM_GPIO 23 +#define AR9565_NUM_GPIO 14 +#define AR9580_NUM_GPIO 16 #define AR7010_NUM_GPIO 16 -#define AR_GPIO_IN_OUT (AR_SREV_9340(ah) ? 0x4028 : 0x4048) +#define AR_GPIO_MASK 0x00003FFF +#define AR9271_GPIO_MASK 0x0000FFFF +#define AR9280_GPIO_MASK 0x000003FF +#define AR9285_GPIO_MASK 0x00000FFF +#define AR9287_GPIO_MASK 0x000003FF +#define AR9300_GPIO_MASK 0x0000F4FF +#define AR9330_GPIO_MASK 0x0000F4FF +#define AR9340_GPIO_MASK 0x0000000F +#define AR9462_GPIO_MASK 0x00003FFF +#define AR9485_GPIO_MASK 0x00000FFF +#define AR9531_GPIO_MASK 0x0000000F +#define AR9550_GPIO_MASK 0x0000000F +#define AR9561_GPIO_MASK 0x0000000F +#define AR9565_GPIO_MASK 0x00003FFF +#define AR9580_GPIO_MASK 0x0000F4FF +#define AR7010_GPIO_MASK 0x0000FFFF + +#define AR_GPIO_IN_OUT(_ah) (AR_SREV_9340(_ah) ? 0x4028 : 0x4048) #define AR_GPIO_IN_VAL 0x0FFFC000 #define AR_GPIO_IN_VAL_S 14 #define AR928X_GPIO_IN_VAL 0x000FFC00 @@ -1084,12 +1170,12 @@ enum { #define AR7010_GPIO_IN_VAL 0x0000FFFF #define AR7010_GPIO_IN_VAL_S 0 -#define AR_GPIO_IN (AR_SREV_9340(ah) ? 0x402c : 0x404c) +#define AR_GPIO_IN(_ah) (AR_SREV_9340(_ah) ? 0x402c : 0x404c) #define AR9300_GPIO_IN_VAL 0x0001FFFF #define AR9300_GPIO_IN_VAL_S 0 -#define AR_GPIO_OE_OUT (AR_SREV_9340(ah) ? 0x4030 : \ - (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)) +#define AR_GPIO_OE_OUT(_ah) (AR_SREV_9340(_ah) ? 0x4030 : \ + (AR_SREV_9300_20_OR_LATER(_ah) ? 0x4050 : 0x404c)) #define AR_GPIO_OE_OUT_DRV 0x3 #define AR_GPIO_OE_OUT_DRV_NO 0x0 #define AR_GPIO_OE_OUT_DRV_LOW 0x1 @@ -1111,13 +1197,13 @@ enum { #define AR7010_GPIO_INT_MASK 0x52024 #define AR7010_GPIO_FUNCTION 0x52028 -#define AR_GPIO_INTR_POL (AR_SREV_9340(ah) ? 0x4038 : \ - (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050)) +#define AR_GPIO_INTR_POL(_ah) (AR_SREV_9340(_ah) ? 0x4038 : \ + (AR_SREV_9300_20_OR_LATER(_ah) ? 0x4058 : 0x4050)) #define AR_GPIO_INTR_POL_VAL 0x0001FFFF #define AR_GPIO_INTR_POL_VAL_S 0 -#define AR_GPIO_INPUT_EN_VAL (AR_SREV_9340(ah) ? 0x403c : \ - (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054)) +#define AR_GPIO_INPUT_EN_VAL(_ah) (AR_SREV_9340(_ah) ? 0x403c : \ + (AR_SREV_9300_20_OR_LATER(_ah) ? 0x405c : 0x4054)) #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF 0x00000004 #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_S 2 #define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF 0x00000008 @@ -1135,15 +1221,15 @@ enum { #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 #define AR_GPIO_JTAG_DISABLE 0x00020000 -#define AR_GPIO_INPUT_MUX1 (AR_SREV_9340(ah) ? 0x4040 : \ - (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058)) +#define AR_GPIO_INPUT_MUX1(_ah) (AR_SREV_9340(_ah) ? 0x4040 : \ + (AR_SREV_9300_20_OR_LATER(_ah) ? 0x4060 : 0x4058)) #define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000 #define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16 #define AR_GPIO_INPUT_MUX1_BT_PRIORITY 0x00000f00 #define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S 8 -#define AR_GPIO_INPUT_MUX2 (AR_SREV_9340(ah) ? 0x4044 : \ - (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c)) +#define AR_GPIO_INPUT_MUX2(_ah) (AR_SREV_9340(_ah) ? 0x4044 : \ + (AR_SREV_9300_20_OR_LATER(_ah) ? 0x4064 : 0x405c)) #define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f #define AR_GPIO_INPUT_MUX2_CLK25_S 0 #define AR_GPIO_INPUT_MUX2_RFSILENT 0x000000f0 @@ -1151,18 +1237,18 @@ enum { #define AR_GPIO_INPUT_MUX2_RTC_RESET 0x00000f00 #define AR_GPIO_INPUT_MUX2_RTC_RESET_S 8 -#define AR_GPIO_OUTPUT_MUX1 (AR_SREV_9340(ah) ? 0x4048 : \ - (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060)) -#define AR_GPIO_OUTPUT_MUX2 (AR_SREV_9340(ah) ? 0x404c : \ - (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064)) -#define AR_GPIO_OUTPUT_MUX3 (AR_SREV_9340(ah) ? 0x4050 : \ - (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068)) +#define AR_GPIO_OUTPUT_MUX1(_ah) (AR_SREV_9340(_ah) ? 0x4048 : \ + (AR_SREV_9300_20_OR_LATER(_ah) ? 0x4068 : 0x4060)) +#define AR_GPIO_OUTPUT_MUX2(_ah) (AR_SREV_9340(_ah) ? 0x404c : \ + (AR_SREV_9300_20_OR_LATER(_ah) ? 0x406c : 0x4064)) +#define AR_GPIO_OUTPUT_MUX3(_ah) (AR_SREV_9340(_ah) ? 0x4050 : \ + (AR_SREV_9300_20_OR_LATER(_ah) ? 0x4070 : 0x4068)) -#define AR_INPUT_STATE (AR_SREV_9340(ah) ? 0x4054 : \ - (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c)) +#define AR_INPUT_STATE(_ah) (AR_SREV_9340(_ah) ? 0x4054 : \ + (AR_SREV_9300_20_OR_LATER(_ah) ? 0x4074 : 0x406c)) -#define AR_EEPROM_STATUS_DATA (AR_SREV_9340(ah) ? 0x40c8 : \ - (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c)) +#define AR_EEPROM_STATUS_DATA(_ah) (AR_SREV_9340(_ah) ? 0x40c8 : \ + (AR_SREV_9300_20_OR_LATER(_ah) ? 0x4084 : 0x407c)) #define AR_EEPROM_STATUS_DATA_VAL 0x0000ffff #define AR_EEPROM_STATUS_DATA_VAL_S 0 #define AR_EEPROM_STATUS_DATA_BUSY 0x00010000 @@ -1170,19 +1256,26 @@ enum { #define AR_EEPROM_STATUS_DATA_PROT_ACCESS 0x00040000 #define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS 0x00080000 -#define AR_OBS (AR_SREV_9340(ah) ? 0x405c : \ - (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080)) +#define AR_OBS(_ah) (AR_SREV_9340(_ah) ? 0x405c : \ + (AR_SREV_9300_20_OR_LATER(_ah) ? 0x4088 : 0x4080)) -#define AR_GPIO_PDPU (AR_SREV_9300_20_OR_LATER(ah) ? 0x4090 : 0x4088) +#define AR_GPIO_PDPU(_ah) (AR_SREV_9300_20_OR_LATER(_ah) ? 0x4090 : 0x4088) -#define AR_PCIE_MSI (AR_SREV_9340(ah) ? 0x40d8 : \ - (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094)) +#define AR_PCIE_MSI(_ah) (AR_SREV_9340(_ah) ? 0x40d8 : \ + (AR_SREV_9300_20_OR_LATER(_ah) ? 0x40a4 : 0x4094)) #define AR_PCIE_MSI_ENABLE 0x00000001 - -#define AR_INTR_PRIO_SYNC_ENABLE (AR_SREV_9340(ah) ? 0x4088 : 0x40c4) -#define AR_INTR_PRIO_ASYNC_MASK (AR_SREV_9340(ah) ? 0x408c : 0x40c8) -#define AR_INTR_PRIO_SYNC_MASK (AR_SREV_9340(ah) ? 0x4090 : 0x40cc) -#define AR_INTR_PRIO_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4094 : 0x40d4) +#define AR_PCIE_MSI_HW_DBI_WR_EN 0x02000000 +#define AR_PCIE_MSI_HW_INT_PENDING_ADDR 0xFFA0C1FF /* bits 8..11: value must be 0x5060 */ +#define AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64 0xFFA0C9FF /* bits 8..11: value must be 0x5064 */ + +#define AR_INTR_PRIO_TX 0x00000001 +#define AR_INTR_PRIO_RXLP 0x00000002 +#define AR_INTR_PRIO_RXHP 0x00000004 + +#define AR_INTR_PRIO_SYNC_ENABLE(_ah) (AR_SREV_9340(_ah) ? 0x4088 : 0x40c4) +#define AR_INTR_PRIO_ASYNC_MASK(_ah) (AR_SREV_9340(_ah) ? 0x408c : 0x40c8) +#define AR_INTR_PRIO_SYNC_MASK(_ah) (AR_SREV_9340(_ah) ? 0x4090 : 0x40cc) +#define AR_INTR_PRIO_ASYNC_ENABLE(_ah) (AR_SREV_9340(_ah) ? 0x4094 : 0x40d4) #define AR_ENT_OTP 0x40d8 #define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000 #define AR_ENT_OTP_49GHZ_DISABLE 0x00100000 @@ -1220,12 +1313,23 @@ enum { #define AR_CH0_DPLL3_PHASE_SHIFT_S 23 #define AR_PHY_CCA_NOM_VAL_2GHZ -118 +#define AR_RTC_9300_SOC_PLL_DIV_INT 0x0000003f +#define AR_RTC_9300_SOC_PLL_DIV_INT_S 0 +#define AR_RTC_9300_SOC_PLL_DIV_FRAC 0x000fffc0 +#define AR_RTC_9300_SOC_PLL_DIV_FRAC_S 6 +#define AR_RTC_9300_SOC_PLL_REFDIV 0x01f00000 +#define AR_RTC_9300_SOC_PLL_REFDIV_S 20 +#define AR_RTC_9300_SOC_PLL_CLKSEL 0x06000000 +#define AR_RTC_9300_SOC_PLL_CLKSEL_S 25 +#define AR_RTC_9300_SOC_PLL_BYPASS 0x08000000 + #define AR_RTC_9300_PLL_DIV 0x000003ff #define AR_RTC_9300_PLL_DIV_S 0 #define AR_RTC_9300_PLL_REFDIV 0x00003C00 #define AR_RTC_9300_PLL_REFDIV_S 10 #define AR_RTC_9300_PLL_CLKSEL 0x0000C000 #define AR_RTC_9300_PLL_CLKSEL_S 14 +#define AR_RTC_9300_PLL_BYPASS 0x00010000 #define AR_RTC_9160_PLL_DIV 0x000003ff #define AR_RTC_9160_PLL_DIV_S 0 @@ -1235,8 +1339,8 @@ enum { #define AR_RTC_9160_PLL_CLKSEL_S 14 #define AR_RTC_BASE 0x00020000 -#define AR_RTC_RC \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0000) : 0x7000) +#define AR_RTC_RC(_ah) \ + ((AR_SREV_9100(_ah)) ? (AR_RTC_BASE + 0x0000) : 0x7000) #define AR_RTC_RC_M 0x00000003 #define AR_RTC_RC_MAC_WARM 0x00000001 #define AR_RTC_RC_MAC_COLD 0x00000002 @@ -1253,8 +1357,8 @@ enum { #define AR_RTC_REG_CONTROL1 0x700c #define AR_RTC_REG_CONTROL1_SWREG_PROGRAM 0x00000001 -#define AR_RTC_PLL_CONTROL \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0014) : 0x7014) +#define AR_RTC_PLL_CONTROL(_ah) \ + ((AR_SREV_9100(_ah)) ? (AR_RTC_BASE + 0x0014) : 0x7014) #define AR_RTC_PLL_CONTROL2 0x703c @@ -1274,15 +1378,15 @@ enum { #define PLL4_MEAS_DONE 0x8 #define SQSUM_DVC_MASK 0x007ffff8 -#define AR_RTC_RESET \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0040) : 0x7040) +#define AR_RTC_RESET(_ah) \ + ((AR_SREV_9100(_ah)) ? (AR_RTC_BASE + 0x0040) : 0x7040) #define AR_RTC_RESET_EN (0x00000001) -#define AR_RTC_STATUS \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0044) : 0x7044) +#define AR_RTC_STATUS(_ah) \ + ((AR_SREV_9100(_ah)) ? (AR_RTC_BASE + 0x0044) : 0x7044) -#define AR_RTC_STATUS_M \ - ((AR_SREV_9100(ah)) ? 0x0000003f : 0x0000000f) +#define AR_RTC_STATUS_M(_ah) \ + ((AR_SREV_9100(_ah)) ? 0x0000003f : 0x0000000f) #define AR_RTC_PM_STATUS_M 0x0000000f @@ -1291,32 +1395,32 @@ enum { #define AR_RTC_STATUS_SLEEP 0x00000004 #define AR_RTC_STATUS_WAKEUP 0x00000008 -#define AR_RTC_SLEEP_CLK \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0048) : 0x7048) +#define AR_RTC_SLEEP_CLK(_ah) \ + ((AR_SREV_9100(_ah)) ? (AR_RTC_BASE + 0x0048) : 0x7048) #define AR_RTC_FORCE_DERIVED_CLK 0x2 #define AR_RTC_FORCE_SWREG_PRD 0x00000004 -#define AR_RTC_FORCE_WAKE \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x004c) : 0x704c) +#define AR_RTC_FORCE_WAKE(_ah) \ + ((AR_SREV_9100(_ah)) ? (AR_RTC_BASE + 0x004c) : 0x704c) #define AR_RTC_FORCE_WAKE_EN 0x00000001 #define AR_RTC_FORCE_WAKE_ON_INT 0x00000002 -#define AR_RTC_INTR_CAUSE \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0050) : 0x7050) +#define AR_RTC_INTR_CAUSE(_ah) \ + ((AR_SREV_9100(_ah)) ? (AR_RTC_BASE + 0x0050) : 0x7050) -#define AR_RTC_INTR_ENABLE \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0054) : 0x7054) +#define AR_RTC_INTR_ENABLE(_ah) \ + ((AR_SREV_9100(_ah)) ? (AR_RTC_BASE + 0x0054) : 0x7054) -#define AR_RTC_INTR_MASK \ - ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058) +#define AR_RTC_INTR_MASK(_ah) \ + ((AR_SREV_9100(_ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058) #define AR_RTC_KEEP_AWAKE 0x7034 /* RTC_DERIVED_* - only for AR9100 */ -#define AR_RTC_DERIVED_CLK \ - (AR_SREV_9100(ah) ? (AR_RTC_BASE + 0x0038) : 0x7038) +#define AR_RTC_DERIVED_CLK(_ah) \ + (AR_SREV_9100(_ah) ? (AR_RTC_BASE + 0x0038) : 0x7038) #define AR_RTC_DERIVED_CLK_PERIOD 0x0000fffe #define AR_RTC_DERIVED_CLK_PERIOD_S 1 @@ -1563,6 +1667,7 @@ enum { #define AR_RESET_TSF 0x8020 #define AR_RESET_TSF_ONCE 0x01000000 +#define AR_RESET_TSF2_ONCE 0x02000000 #define AR_MAX_CFP_DUR 0x8038 #define AR_CFP_VAL 0x0000FFFF @@ -1681,6 +1786,8 @@ enum { #define AR_TPC_CTS_S 8 #define AR_TPC_CHIRP 0x003f0000 #define AR_TPC_CHIRP_S 16 +#define AR_TPC_RPT 0x3f000000 +#define AR_TPC_RPT_S 24 #define AR_QUIET1 0x80fc #define AR_QUIET1_NEXT_QUIET_S 0 @@ -1800,15 +1907,33 @@ enum { #define AR9300_BT_WGHT 0xcccc4444 -#define AR_BT_COEX_MODE2 0x817c -#define AR_BT_BCN_MISS_THRESH 0x000000ff -#define AR_BT_BCN_MISS_THRESH_S 0 -#define AR_BT_BCN_MISS_CNT 0x0000ff00 -#define AR_BT_BCN_MISS_CNT_S 8 -#define AR_BT_HOLD_RX_CLEAR 0x00010000 -#define AR_BT_HOLD_RX_CLEAR_S 16 -#define AR_BT_DISABLE_BT_ANT 0x00100000 -#define AR_BT_DISABLE_BT_ANT_S 20 +#define AR_BT_COEX_MODE2 0x817c +#define AR_BT_BCN_MISS_THRESH 0x000000ff +#define AR_BT_BCN_MISS_THRESH_S 0 +#define AR_BT_BCN_MISS_CNT 0x0000ff00 +#define AR_BT_BCN_MISS_CNT_S 8 +#define AR_BT_HOLD_RX_CLEAR 0x00010000 +#define AR_BT_HOLD_RX_CLEAR_S 16 +#define AR_BT_PROTECT_BT_AFTER_WAKEUP 0x00080000 +#define AR_BT_PROTECT_BT_AFTER_WAKEUP_S 19 +#define AR_BT_DISABLE_BT_ANT 0x00100000 +#define AR_BT_DISABLE_BT_ANT_S 20 +#define AR_BT_QUIET_2_WIRE 0x00200000 +#define AR_BT_QUIET_2_WIRE_S 21 +#define AR_BT_WL_ACTIVE_MODE 0x00c00000 +#define AR_BT_WL_ACTIVE_MODE_S 22 +#define AR_BT_WL_TXRX_SEPARATE 0x01000000 +#define AR_BT_WL_TXRX_SEPARATE_S 24 +#define AR_BT_RS_DISCARD_EXTEND 0x02000000 +#define AR_BT_RS_DISCARD_EXTEND_S 25 +#define AR_BT_TSF_BT_ACTIVE_CTRL 0x0c000000 +#define AR_BT_TSF_BT_ACTIVE_CTRL_S 26 +#define AR_BT_TSF_BT_PRIORITY_CTRL 0x30000000 +#define AR_BT_TSF_BT_PRIORITY_CTRL_S 28 +#define AR_BT_INTERRUPT_ENABLE 0x40000000 +#define AR_BT_INTERRUPT_ENABLE_S 30 +#define AR_BT_PHY_ERR_BT_COLL_ENABLE 0x80000000 +#define AR_BT_PHY_ERR_BT_COLL_ENABLE_S 31 #define AR_TXSIFS 0x81d0 #define AR_TXSIFS_TIME 0x000000FF @@ -1817,6 +1942,16 @@ enum { #define AR_TXSIFS_ACK_SHIFT 0x00007000 #define AR_TXSIFS_ACK_SHIFT_S 12 +#define AR_BT_COEX_MODE3 0x81d4 +#define AR_BT_WL_ACTIVE_TIME 0x000000ff +#define AR_BT_WL_ACTIVE_TIME_S 0 +#define AR_BT_WL_QC_TIME 0x0000ff00 +#define AR_BT_WL_QC_TIME_S 8 +#define AR_BT_ALLOW_CONCURRENT_ACCESS 0x000f0000 +#define AR_BT_ALLOW_CONCURRENT_ACCESS_S 16 +#define AR_BT_AGC_SATURATION_CNT_ENABLE 0x00100000 +#define AR_BT_AGC_SATURATION_CNT_ENABLE_S 20 + #define AR_TXOP_X 0x81ec #define AR_TXOP_X_VAL 0x000000FF @@ -1831,6 +1966,7 @@ enum { #define AR_FIRST_NDP_TIMER 7 #define AR_NDP2_PERIOD 0x81a0 #define AR_NDP2_TIMER_MODE 0x81c0 +#define AR_GEN_TIMERS2_MODE_ENABLE_MASK 0x000000FF #define AR_GEN_TIMERS(_i) (0x8200 + ((_i) << 2)) #define AR_NEXT_TBTT_TIMER AR_GEN_TIMERS(0) @@ -1924,6 +2060,9 @@ enum { #define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000 #define AR_MAC_PCU_GEN_TIMER_TSF_SEL 0x83d8 +#define AR_DIRECT_CONNECT 0x83a0 +#define AR_DC_AP_STA_EN 0x00000001 +#define AR_DC_TSF2_ENABLE 0x00000001 #define AR_AES_MUTE_MASK0 0x805c #define AR_AES_MUTE_MASK0_FC 0x0000FFFF @@ -1956,126 +2095,6 @@ enum { #define AR_WOW_BEACON_TIMO_MAX 0xffffffff -/* - * MAC WoW Registers - */ - -#define AR_WOW_PATTERN 0x825C -#define AR_WOW_COUNT 0x8260 -#define AR_WOW_BCN_EN 0x8270 -#define AR_WOW_BCN_TIMO 0x8274 -#define AR_WOW_KEEP_ALIVE_TIMO 0x8278 -#define AR_WOW_KEEP_ALIVE 0x827c -#define AR_WOW_US_SCALAR 0x8284 -#define AR_WOW_KEEP_ALIVE_DELAY 0x8288 -#define AR_WOW_PATTERN_MATCH 0x828c -#define AR_WOW_PATTERN_OFF1 0x8290 /* pattern bytes 0 -> 3 */ -#define AR_WOW_PATTERN_OFF2 0x8294 /* pattern bytes 4 -> 7 */ - -/* for AR9285 or later version of chips */ -#define AR_WOW_EXACT 0x829c -#define AR_WOW_LENGTH1 0x8360 -#define AR_WOW_LENGTH2 0X8364 -/* register to enable match for less than 256 bytes packets */ -#define AR_WOW_PATTERN_MATCH_LT_256B 0x8368 - -#define AR_SW_WOW_CONTROL 0x20018 -#define AR_SW_WOW_ENABLE 0x1 -#define AR_SWITCH_TO_REFCLK 0x2 -#define AR_RESET_CONTROL 0x4 -#define AR_RESET_VALUE_MASK 0x8 -#define AR_HW_WOW_DISABLE 0x10 -#define AR_CLR_MAC_INTERRUPT 0x20 -#define AR_CLR_KA_INTERRUPT 0x40 - -/* AR_WOW_PATTERN register values */ -#define AR_WOW_BACK_OFF_SHIFT(x) ((x & 0xf) << 28) /* in usecs */ -#define AR_WOW_MAC_INTR_EN 0x00040000 -#define AR_WOW_MAGIC_EN 0x00010000 -#define AR_WOW_PATTERN_EN(x) (x & 0xff) -#define AR_WOW_PAT_FOUND_SHIFT 8 -#define AR_WOW_PATTERN_FOUND(x) (x & (0xff << AR_WOW_PAT_FOUND_SHIFT)) -#define AR_WOW_PATTERN_FOUND_MASK ((0xff) << AR_WOW_PAT_FOUND_SHIFT) -#define AR_WOW_MAGIC_PAT_FOUND 0x00020000 -#define AR_WOW_MAC_INTR 0x00080000 -#define AR_WOW_KEEP_ALIVE_FAIL 0x00100000 -#define AR_WOW_BEACON_FAIL 0x00200000 - -#define AR_WOW_STATUS(x) (x & (AR_WOW_PATTERN_FOUND_MASK | \ - AR_WOW_MAGIC_PAT_FOUND | \ - AR_WOW_KEEP_ALIVE_FAIL | \ - AR_WOW_BEACON_FAIL)) -#define AR_WOW_CLEAR_EVENTS(x) (x & ~(AR_WOW_PATTERN_EN(0xff) | \ - AR_WOW_MAGIC_EN | \ - AR_WOW_MAC_INTR_EN | \ - AR_WOW_BEACON_FAIL | \ - AR_WOW_KEEP_ALIVE_FAIL)) - -/* AR_WOW_COUNT register values */ -#define AR_WOW_AIFS_CNT(x) (x & 0xff) -#define AR_WOW_SLOT_CNT(x) ((x & 0xff) << 8) -#define AR_WOW_KEEP_ALIVE_CNT(x) ((x & 0xff) << 16) - -/* AR_WOW_BCN_EN register */ -#define AR_WOW_BEACON_FAIL_EN 0x00000001 - -/* AR_WOW_BCN_TIMO rgister */ -#define AR_WOW_BEACON_TIMO 0x40000000 /* valid if BCN_EN is set */ - -/* AR_WOW_KEEP_ALIVE_TIMO register */ -#define AR_WOW_KEEP_ALIVE_TIMO_VALUE -#define AR_WOW_KEEP_ALIVE_NEVER 0xffffffff - -/* AR_WOW_KEEP_ALIVE register */ -#define AR_WOW_KEEP_ALIVE_AUTO_DIS 0x00000001 -#define AR_WOW_KEEP_ALIVE_FAIL_DIS 0x00000002 - -/* AR_WOW_KEEP_ALIVE_DELAY register */ -#define AR_WOW_KEEP_ALIVE_DELAY_VALUE 0x000003e8 /* 1 msec */ - - -/* - * keep it long for beacon workaround - ensure no false alarm - */ -#define AR_WOW_BMISSTHRESHOLD 0x20 - -/* AR_WOW_PATTERN_MATCH register */ -#define AR_WOW_PAT_END_OF_PKT(x) (x & 0xf) -#define AR_WOW_PAT_OFF_MATCH(x) ((x & 0xf) << 8) - -/* - * default values for Wow Configuration for backoff, aifs, slot, keep-alive - * to be programmed into various registers. - */ -#define AR_WOW_PAT_BACKOFF 0x00000004 /* AR_WOW_PATTERN_REG */ -#define AR_WOW_CNT_AIFS_CNT 0x00000022 /* AR_WOW_COUNT_REG */ -#define AR_WOW_CNT_SLOT_CNT 0x00000009 /* AR_WOW_COUNT_REG */ -/* - * Keepalive count applicable for AR9280 2.0 and above. - */ -#define AR_WOW_CNT_KA_CNT 0x00000008 /* AR_WOW_COUNT register */ - -/* WoW - Transmit buffer for keep alive frames */ -#define AR_WOW_TRANSMIT_BUFFER 0xe000 /* E000 - EFFC */ - -#define AR_WOW_TXBUF(i) (AR_WOW_TRANSMIT_BUFFER + ((i) << 2)) - -#define AR_WOW_KA_DESC_WORD2 0xe000 - -#define AR_WOW_KA_DATA_WORD0 0xe030 - -/* WoW Transmit Buffer for patterns */ -#define AR_WOW_TB_PATTERN(i) (0xe100 + (i << 8)) -#define AR_WOW_TB_MASK(i) (0xec00 + (i << 5)) - -/* Currently Pattern 0-7 are supported - so bit 0-7 are set */ -#define AR_WOW_PATTERN_SUPPORTED 0xff -#define AR_WOW_LENGTH_MAX 0xff -#define AR_WOW_LEN1_SHIFT(_i) ((0x3 - ((_i) & 0x3)) << 0x3) -#define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i)) -#define AR_WOW_LEN2_SHIFT(_i) ((0x7 - ((_i) & 0x7)) << 0x3) -#define AR_WOW_LENGTH2_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN2_SHIFT(_i)) - #define AR9271_CORE_CLOCK 117 /* clock to 117Mhz */ #define AR9271_TARGET_BAUD_RATE 19200 /* 115200 */ @@ -2095,7 +2114,7 @@ enum { #define AR9300_SM_BASE 0xa200 #define AR9002_PHY_AGC_CONTROL 0x9860 #define AR9003_PHY_AGC_CONTROL AR9300_SM_BASE + 0xc4 -#define AR_PHY_AGC_CONTROL (AR_SREV_9300_20_OR_LATER(ah) ? AR9003_PHY_AGC_CONTROL : AR9002_PHY_AGC_CONTROL) +#define AR_PHY_AGC_CONTROL(_ah) (AR_SREV_9300_20_OR_LATER(_ah) ? AR9003_PHY_AGC_CONTROL : AR9002_PHY_AGC_CONTROL) #define AR_PHY_AGC_CONTROL_CAL 0x00000001 /* do internal calibration */ #define AR_PHY_AGC_CONTROL_NF 0x00000002 /* do noise-floor calibration */ #define AR_PHY_AGC_CONTROL_OFFSET_CAL 0x00000800 /* allow offset calibration */ @@ -2108,279 +2127,4 @@ enum { #define AR_PHY_AGC_CONTROL_YCOK_MAX 0x000003c0 #define AR_PHY_AGC_CONTROL_YCOK_MAX_S 6 -/* MCI Registers */ - -#define AR_MCI_COMMAND0 0x1800 -#define AR_MCI_COMMAND0_HEADER 0xFF -#define AR_MCI_COMMAND0_HEADER_S 0 -#define AR_MCI_COMMAND0_LEN 0x1f00 -#define AR_MCI_COMMAND0_LEN_S 8 -#define AR_MCI_COMMAND0_DISABLE_TIMESTAMP 0x2000 -#define AR_MCI_COMMAND0_DISABLE_TIMESTAMP_S 13 - -#define AR_MCI_COMMAND1 0x1804 - -#define AR_MCI_COMMAND2 0x1808 -#define AR_MCI_COMMAND2_RESET_TX 0x01 -#define AR_MCI_COMMAND2_RESET_TX_S 0 -#define AR_MCI_COMMAND2_RESET_RX 0x02 -#define AR_MCI_COMMAND2_RESET_RX_S 1 -#define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES 0x3FC -#define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES_S 2 -#define AR_MCI_COMMAND2_RESET_REQ_WAKEUP 0x400 -#define AR_MCI_COMMAND2_RESET_REQ_WAKEUP_S 10 - -#define AR_MCI_RX_CTRL 0x180c - -#define AR_MCI_TX_CTRL 0x1810 -/* 0 = no division, 1 = divide by 2, 2 = divide by 4, 3 = divide by 8 */ -#define AR_MCI_TX_CTRL_CLK_DIV 0x03 -#define AR_MCI_TX_CTRL_CLK_DIV_S 0 -#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE 0x04 -#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE_S 2 -#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ 0xFFFFF8 -#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ_S 3 -#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM 0xF000000 -#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM_S 24 - -#define AR_MCI_MSG_ATTRIBUTES_TABLE 0x1814 -#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM 0xFFFF -#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM_S 0 -#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR 0xFFFF0000 -#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR_S 16 - -#define AR_MCI_SCHD_TABLE_0 0x1818 -#define AR_MCI_SCHD_TABLE_1 0x181c -#define AR_MCI_GPM_0 0x1820 -#define AR_MCI_GPM_1 0x1824 -#define AR_MCI_GPM_WRITE_PTR 0xFFFF0000 -#define AR_MCI_GPM_WRITE_PTR_S 16 -#define AR_MCI_GPM_BUF_LEN 0x0000FFFF -#define AR_MCI_GPM_BUF_LEN_S 0 - -#define AR_MCI_INTERRUPT_RAW 0x1828 -#define AR_MCI_INTERRUPT_EN 0x182c -#define AR_MCI_INTERRUPT_SW_MSG_DONE 0x00000001 -#define AR_MCI_INTERRUPT_SW_MSG_DONE_S 0 -#define AR_MCI_INTERRUPT_CPU_INT_MSG 0x00000002 -#define AR_MCI_INTERRUPT_CPU_INT_MSG_S 1 -#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL 0x00000004 -#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL_S 2 -#define AR_MCI_INTERRUPT_RX_INVALID_HDR 0x00000008 -#define AR_MCI_INTERRUPT_RX_INVALID_HDR_S 3 -#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL 0x00000010 -#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL_S 4 -#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL 0x00000020 -#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL_S 5 -#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL 0x00000080 -#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL_S 7 -#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL 0x00000100 -#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL_S 8 -#define AR_MCI_INTERRUPT_RX_MSG 0x00000200 -#define AR_MCI_INTERRUPT_RX_MSG_S 9 -#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE 0x00000400 -#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE_S 10 -#define AR_MCI_INTERRUPT_BT_PRI 0x07fff800 -#define AR_MCI_INTERRUPT_BT_PRI_S 11 -#define AR_MCI_INTERRUPT_BT_PRI_THRESH 0x08000000 -#define AR_MCI_INTERRUPT_BT_PRI_THRESH_S 27 -#define AR_MCI_INTERRUPT_BT_FREQ 0x10000000 -#define AR_MCI_INTERRUPT_BT_FREQ_S 28 -#define AR_MCI_INTERRUPT_BT_STOMP 0x20000000 -#define AR_MCI_INTERRUPT_BT_STOMP_S 29 -#define AR_MCI_INTERRUPT_BB_AIC_IRQ 0x40000000 -#define AR_MCI_INTERRUPT_BB_AIC_IRQ_S 30 -#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT 0x80000000 -#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT_S 31 - -#define AR_MCI_INTERRUPT_DEFAULT (AR_MCI_INTERRUPT_SW_MSG_DONE | \ - AR_MCI_INTERRUPT_RX_INVALID_HDR | \ - AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \ - AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \ - AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \ - AR_MCI_INTERRUPT_TX_SW_MSG_FAIL | \ - AR_MCI_INTERRUPT_RX_MSG | \ - AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE | \ - AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT) - -#define AR_MCI_INTERRUPT_MSG_FAIL_MASK (AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \ - AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \ - AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \ - AR_MCI_INTERRUPT_TX_SW_MSG_FAIL) - -#define AR_MCI_REMOTE_CPU_INT 0x1830 -#define AR_MCI_REMOTE_CPU_INT_EN 0x1834 -#define AR_MCI_INTERRUPT_RX_MSG_RAW 0x1838 -#define AR_MCI_INTERRUPT_RX_MSG_EN 0x183c -#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET 0x00000001 -#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET_S 0 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL 0x00000002 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL_S 1 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK 0x00000004 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK_S 2 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO 0x00000008 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO_S 3 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST 0x00000010 -#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST_S 4 -#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO 0x00000020 -#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO_S 5 -#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT 0x00000040 -#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT_S 6 -#define AR_MCI_INTERRUPT_RX_MSG_GPM 0x00000100 -#define AR_MCI_INTERRUPT_RX_MSG_GPM_S 8 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO 0x00000200 -#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO_S 9 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING 0x00000400 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING_S 10 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING 0x00000800 -#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING_S 11 -#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE 0x00001000 -#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE_S 12 -#define AR_MCI_INTERRUPT_RX_HW_MSG_MASK (AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \ - AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL| \ - AR_MCI_INTERRUPT_RX_MSG_LNA_INFO | \ - AR_MCI_INTERRUPT_RX_MSG_CONT_NACK | \ - AR_MCI_INTERRUPT_RX_MSG_CONT_INFO | \ - AR_MCI_INTERRUPT_RX_MSG_CONT_RST) - -#define AR_MCI_INTERRUPT_RX_MSG_DEFAULT (AR_MCI_INTERRUPT_RX_MSG_GPM | \ - AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET| \ - AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING | \ - AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING| \ - AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) - -#define AR_MCI_CPU_INT 0x1840 - -#define AR_MCI_RX_STATUS 0x1844 -#define AR_MCI_RX_LAST_SCHD_MSG_INDEX 0x00000F00 -#define AR_MCI_RX_LAST_SCHD_MSG_INDEX_S 8 -#define AR_MCI_RX_REMOTE_SLEEP 0x00001000 -#define AR_MCI_RX_REMOTE_SLEEP_S 12 -#define AR_MCI_RX_MCI_CLK_REQ 0x00002000 -#define AR_MCI_RX_MCI_CLK_REQ_S 13 - -#define AR_MCI_CONT_STATUS 0x1848 -#define AR_MCI_CONT_RSSI_POWER 0x000000FF -#define AR_MCI_CONT_RSSI_POWER_S 0 -#define AR_MCI_CONT_PRIORITY 0x0000FF00 -#define AR_MCI_CONT_PRIORITY_S 8 -#define AR_MCI_CONT_TXRX 0x00010000 -#define AR_MCI_CONT_TXRX_S 16 - -#define AR_MCI_BT_PRI0 0x184c -#define AR_MCI_BT_PRI1 0x1850 -#define AR_MCI_BT_PRI2 0x1854 -#define AR_MCI_BT_PRI3 0x1858 -#define AR_MCI_BT_PRI 0x185c -#define AR_MCI_WL_FREQ0 0x1860 -#define AR_MCI_WL_FREQ1 0x1864 -#define AR_MCI_WL_FREQ2 0x1868 -#define AR_MCI_GAIN 0x186c -#define AR_MCI_WBTIMER1 0x1870 -#define AR_MCI_WBTIMER2 0x1874 -#define AR_MCI_WBTIMER3 0x1878 -#define AR_MCI_WBTIMER4 0x187c -#define AR_MCI_MAXGAIN 0x1880 -#define AR_MCI_HW_SCHD_TBL_CTL 0x1884 -#define AR_MCI_HW_SCHD_TBL_D0 0x1888 -#define AR_MCI_HW_SCHD_TBL_D1 0x188c -#define AR_MCI_HW_SCHD_TBL_D2 0x1890 -#define AR_MCI_HW_SCHD_TBL_D3 0x1894 -#define AR_MCI_TX_PAYLOAD0 0x1898 -#define AR_MCI_TX_PAYLOAD1 0x189c -#define AR_MCI_TX_PAYLOAD2 0x18a0 -#define AR_MCI_TX_PAYLOAD3 0x18a4 -#define AR_BTCOEX_WBTIMER 0x18a8 - -#define AR_BTCOEX_CTRL 0x18ac -#define AR_BTCOEX_CTRL_AR9462_MODE 0x00000001 -#define AR_BTCOEX_CTRL_AR9462_MODE_S 0 -#define AR_BTCOEX_CTRL_WBTIMER_EN 0x00000002 -#define AR_BTCOEX_CTRL_WBTIMER_EN_S 1 -#define AR_BTCOEX_CTRL_MCI_MODE_EN 0x00000004 -#define AR_BTCOEX_CTRL_MCI_MODE_EN_S 2 -#define AR_BTCOEX_CTRL_LNA_SHARED 0x00000008 -#define AR_BTCOEX_CTRL_LNA_SHARED_S 3 -#define AR_BTCOEX_CTRL_PA_SHARED 0x00000010 -#define AR_BTCOEX_CTRL_PA_SHARED_S 4 -#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN 0x00000020 -#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN_S 5 -#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN 0x00000040 -#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN_S 6 -#define AR_BTCOEX_CTRL_NUM_ANTENNAS 0x00000180 -#define AR_BTCOEX_CTRL_NUM_ANTENNAS_S 7 -#define AR_BTCOEX_CTRL_RX_CHAIN_MASK 0x00000E00 -#define AR_BTCOEX_CTRL_RX_CHAIN_MASK_S 9 -#define AR_BTCOEX_CTRL_AGGR_THRESH 0x00007000 -#define AR_BTCOEX_CTRL_AGGR_THRESH_S 12 -#define AR_BTCOEX_CTRL_1_CHAIN_BCN 0x00080000 -#define AR_BTCOEX_CTRL_1_CHAIN_BCN_S 19 -#define AR_BTCOEX_CTRL_1_CHAIN_ACK 0x00100000 -#define AR_BTCOEX_CTRL_1_CHAIN_ACK_S 20 -#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN 0x1FE00000 -#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN_S 28 -#define AR_BTCOEX_CTRL_REDUCE_TXPWR 0x20000000 -#define AR_BTCOEX_CTRL_REDUCE_TXPWR_S 29 -#define AR_BTCOEX_CTRL_SPDT_ENABLE_10 0x40000000 -#define AR_BTCOEX_CTRL_SPDT_ENABLE_10_S 30 -#define AR_BTCOEX_CTRL_SPDT_POLARITY 0x80000000 -#define AR_BTCOEX_CTRL_SPDT_POLARITY_S 31 - -#define AR_BTCOEX_MAX_TXPWR(_x) (0x18c0 + ((_x) << 2)) -#define AR_BTCOEX_WL_LNA 0x1940 -#define AR_BTCOEX_RFGAIN_CTRL 0x1944 -#define AR_BTCOEX_WL_LNA_TIMEOUT 0x003FFFFF -#define AR_BTCOEX_WL_LNA_TIMEOUT_S 0 - -#define AR_BTCOEX_CTRL2 0x1948 -#define AR_BTCOEX_CTRL2_TXPWR_THRESH 0x0007F800 -#define AR_BTCOEX_CTRL2_TXPWR_THRESH_S 11 -#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK 0x00380000 -#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK_S 19 -#define AR_BTCOEX_CTRL2_RX_DEWEIGHT 0x00400000 -#define AR_BTCOEX_CTRL2_RX_DEWEIGHT_S 22 -#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL 0x00800000 -#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL_S 23 -#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL 0x01000000 -#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL_S 24 -#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE 0x02000000 -#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE_S 25 - -#define AR_BTCOEX_CTRL_SPDT_ENABLE 0x00000001 -#define AR_BTCOEX_CTRL_SPDT_ENABLE_S 0 -#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL 0x00000002 -#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL_S 1 -#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT 0x00000004 -#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT_S 2 -#define AR_GLB_WLAN_UART_INTF_EN 0x00020000 -#define AR_GLB_WLAN_UART_INTF_EN_S 17 -#define AR_GLB_DS_JTAG_DISABLE 0x00040000 -#define AR_GLB_DS_JTAG_DISABLE_S 18 - -#define AR_BTCOEX_RC 0x194c -#define AR_BTCOEX_MAX_RFGAIN(_x) (0x1950 + ((_x) << 2)) -#define AR_BTCOEX_DBG 0x1a50 -#define AR_MCI_LAST_HW_MSG_HDR 0x1a54 -#define AR_MCI_LAST_HW_MSG_BDY 0x1a58 - -#define AR_MCI_SCHD_TABLE_2 0x1a5c -#define AR_MCI_SCHD_TABLE_2_MEM_BASED 0x00000001 -#define AR_MCI_SCHD_TABLE_2_MEM_BASED_S 0 -#define AR_MCI_SCHD_TABLE_2_HW_BASED 0x00000002 -#define AR_MCI_SCHD_TABLE_2_HW_BASED_S 1 - -#define AR_BTCOEX_CTRL3 0x1a60 -#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT 0x00000fff -#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT_S 0 - -#define AR_GLB_SWREG_DISCONT_MODE 0x2002c -#define AR_GLB_SWREG_DISCONT_EN_BT_WLAN 0x3 - -#define AR_MCI_MISC 0x1a74 -#define AR_MCI_MISC_HW_FIX_EN 0x00000001 -#define AR_MCI_MISC_HW_FIX_EN_S 0 -#define AR_MCI_DBG_CNT_CTRL 0x1a78 -#define AR_MCI_DBG_CNT_CTRL_ENABLE 0x00000001 -#define AR_MCI_DBG_CNT_CTRL_ENABLE_S 0 - #endif diff --git a/drivers/net/wireless/ath/ath9k/reg_aic.h b/drivers/net/wireless/ath/ath9k/reg_aic.h new file mode 100644 index 000000000000..f50994910eae --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/reg_aic.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef REG_AIC_H +#define REG_AIC_H + +#define AR_PHY_AIC_CTRL_0_B0 (AR_SM_BASE + 0x4b0) +#define AR_PHY_AIC_CTRL_1_B0 (AR_SM_BASE + 0x4b4) +#define AR_PHY_AIC_CTRL_2_B0 (AR_SM_BASE + 0x4b8) +#define AR_PHY_AIC_CTRL_3_B0 (AR_SM_BASE + 0x4bc) +#define AR_PHY_AIC_CTRL_4_B0 (AR_SM_BASE + 0x4c0) + +#define AR_PHY_AIC_STAT_0_B0 (AR_SM_BASE + 0x4c4) +#define AR_PHY_AIC_STAT_1_B0 (AR_SM_BASE + 0x4c8) +#define AR_PHY_AIC_STAT_2_B0 (AR_SM_BASE + 0x4cc) + +#define AR_PHY_AIC_CTRL_0_B1 (AR_SM1_BASE + 0x4b0) +#define AR_PHY_AIC_CTRL_1_B1 (AR_SM1_BASE + 0x4b4) +#define AR_PHY_AIC_CTRL_4_B1 (AR_SM1_BASE + 0x4c0) + +#define AR_PHY_AIC_STAT_0_B1 (AR_SM1_BASE + 0x4c4) +#define AR_PHY_AIC_STAT_1_B1 (AR_SM1_BASE + 0x4c8) +#define AR_PHY_AIC_STAT_2_B1 (AR_SM1_BASE + 0x4cc) + +#define AR_PHY_AIC_SRAM_ADDR_B0 (AR_SM_BASE + 0x5f0) +#define AR_PHY_AIC_SRAM_DATA_B0 (AR_SM_BASE + 0x5f4) + +#define AR_PHY_AIC_SRAM_ADDR_B1 (AR_SM1_BASE + 0x5f0) +#define AR_PHY_AIC_SRAM_DATA_B1 (AR_SM1_BASE + 0x5f4) + +#define AR_PHY_BT_COEX_4 (AR_AGC_BASE + 0x60) +#define AR_PHY_BT_COEX_5 (AR_AGC_BASE + 0x64) + +/* AIC fields */ +#define AR_PHY_AIC_MON_ENABLE 0x80000000 +#define AR_PHY_AIC_MON_ENABLE_S 31 +#define AR_PHY_AIC_CAL_MAX_HOP_COUNT 0x7F000000 +#define AR_PHY_AIC_CAL_MAX_HOP_COUNT_S 24 +#define AR_PHY_AIC_CAL_MIN_VALID_COUNT 0x00FE0000 +#define AR_PHY_AIC_CAL_MIN_VALID_COUNT_S 17 +#define AR_PHY_AIC_F_WLAN 0x0001FC00 +#define AR_PHY_AIC_F_WLAN_S 10 +#define AR_PHY_AIC_CAL_CH_VALID_RESET 0x00000200 +#define AR_PHY_AIC_CAL_CH_VALID_RESET_S 9 +#define AR_PHY_AIC_CAL_ENABLE 0x00000100 +#define AR_PHY_AIC_CAL_ENABLE_S 8 +#define AR_PHY_AIC_BTTX_PWR_THR 0x000000FE +#define AR_PHY_AIC_BTTX_PWR_THR_S 1 +#define AR_PHY_AIC_ENABLE 0x00000001 +#define AR_PHY_AIC_ENABLE_S 0 +#define AR_PHY_AIC_CAL_BT_REF_DELAY 0x00F00000 +#define AR_PHY_AIC_CAL_BT_REF_DELAY_S 20 +#define AR_PHY_AIC_BT_IDLE_CFG 0x00080000 +#define AR_PHY_AIC_BT_IDLE_CFG_S 19 +#define AR_PHY_AIC_STDBY_COND 0x00060000 +#define AR_PHY_AIC_STDBY_COND_S 17 +#define AR_PHY_AIC_STDBY_ROT_ATT_DB 0x0001F800 +#define AR_PHY_AIC_STDBY_ROT_ATT_DB_S 11 +#define AR_PHY_AIC_STDBY_COM_ATT_DB 0x00000700 +#define AR_PHY_AIC_STDBY_COM_ATT_DB_S 8 +#define AR_PHY_AIC_RSSI_MAX 0x000000F0 +#define AR_PHY_AIC_RSSI_MAX_S 4 +#define AR_PHY_AIC_RSSI_MIN 0x0000000F +#define AR_PHY_AIC_RSSI_MIN_S 0 +#define AR_PHY_AIC_RADIO_DELAY 0x7F000000 +#define AR_PHY_AIC_RADIO_DELAY_S 24 +#define AR_PHY_AIC_CAL_STEP_SIZE_CORR 0x00F00000 +#define AR_PHY_AIC_CAL_STEP_SIZE_CORR_S 20 +#define AR_PHY_AIC_CAL_ROT_IDX_CORR 0x000F8000 +#define AR_PHY_AIC_CAL_ROT_IDX_CORR_S 15 +#define AR_PHY_AIC_CAL_CONV_CHECK_FACTOR 0x00006000 +#define AR_PHY_AIC_CAL_CONV_CHECK_FACTOR_S 13 +#define AR_PHY_AIC_ROT_IDX_COUNT_MAX 0x00001C00 +#define AR_PHY_AIC_ROT_IDX_COUNT_MAX_S 10 +#define AR_PHY_AIC_CAL_SYNTH_TOGGLE 0x00000200 +#define AR_PHY_AIC_CAL_SYNTH_TOGGLE_S 9 +#define AR_PHY_AIC_CAL_SYNTH_AFTER_BTRX 0x00000100 +#define AR_PHY_AIC_CAL_SYNTH_AFTER_BTRX_S 8 +#define AR_PHY_AIC_CAL_SYNTH_SETTLING 0x000000FF +#define AR_PHY_AIC_CAL_SYNTH_SETTLING_S 0 +#define AR_PHY_AIC_MON_MAX_HOP_COUNT 0x07F00000 +#define AR_PHY_AIC_MON_MAX_HOP_COUNT_S 20 +#define AR_PHY_AIC_MON_MIN_STALE_COUNT 0x000FE000 +#define AR_PHY_AIC_MON_MIN_STALE_COUNT_S 13 +#define AR_PHY_AIC_MON_PWR_EST_LONG 0x00001000 +#define AR_PHY_AIC_MON_PWR_EST_LONG_S 12 +#define AR_PHY_AIC_MON_PD_TALLY_SCALING 0x00000C00 +#define AR_PHY_AIC_MON_PD_TALLY_SCALING_S 10 +#define AR_PHY_AIC_MON_PERF_THR 0x000003E0 +#define AR_PHY_AIC_MON_PERF_THR_S 5 +#define AR_PHY_AIC_CAL_TARGET_MAG_SETTING 0x00000018 +#define AR_PHY_AIC_CAL_TARGET_MAG_SETTING_S 3 +#define AR_PHY_AIC_CAL_PERF_CHECK_FACTOR 0x00000006 +#define AR_PHY_AIC_CAL_PERF_CHECK_FACTOR_S 1 +#define AR_PHY_AIC_CAL_PWR_EST_LONG 0x00000001 +#define AR_PHY_AIC_CAL_PWR_EST_LONG_S 0 +#define AR_PHY_AIC_MON_DONE 0x80000000 +#define AR_PHY_AIC_MON_DONE_S 31 +#define AR_PHY_AIC_MON_ACTIVE 0x40000000 +#define AR_PHY_AIC_MON_ACTIVE_S 30 +#define AR_PHY_AIC_MEAS_COUNT 0x3F000000 +#define AR_PHY_AIC_MEAS_COUNT_S 24 +#define AR_PHY_AIC_CAL_ANT_ISO_EST 0x00FC0000 +#define AR_PHY_AIC_CAL_ANT_ISO_EST_S 18 +#define AR_PHY_AIC_CAL_HOP_COUNT 0x0003F800 +#define AR_PHY_AIC_CAL_HOP_COUNT_S 11 +#define AR_PHY_AIC_CAL_VALID_COUNT 0x000007F0 +#define AR_PHY_AIC_CAL_VALID_COUNT_S 4 +#define AR_PHY_AIC_CAL_BT_TOO_WEAK_ERR 0x00000008 +#define AR_PHY_AIC_CAL_BT_TOO_WEAK_ERR_S 3 +#define AR_PHY_AIC_CAL_BT_TOO_STRONG_ERR 0x00000004 +#define AR_PHY_AIC_CAL_BT_TOO_STRONG_ERR_S 2 +#define AR_PHY_AIC_CAL_DONE 0x00000002 +#define AR_PHY_AIC_CAL_DONE_S 1 +#define AR_PHY_AIC_CAL_ACTIVE 0x00000001 +#define AR_PHY_AIC_CAL_ACTIVE_S 0 + +#define AR_PHY_AIC_MEAS_MAG_MIN 0xFFC00000 +#define AR_PHY_AIC_MEAS_MAG_MIN_S 22 +#define AR_PHY_AIC_MON_STALE_COUNT 0x003F8000 +#define AR_PHY_AIC_MON_STALE_COUNT_S 15 +#define AR_PHY_AIC_MON_HOP_COUNT 0x00007F00 +#define AR_PHY_AIC_MON_HOP_COUNT_S 8 +#define AR_PHY_AIC_CAL_AIC_SM 0x000000F8 +#define AR_PHY_AIC_CAL_AIC_SM_S 3 +#define AR_PHY_AIC_SM 0x00000007 +#define AR_PHY_AIC_SM_S 0 +#define AR_PHY_AIC_SRAM_VALID 0x00000001 +#define AR_PHY_AIC_SRAM_VALID_S 0 +#define AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB 0x0000007E +#define AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB_S 1 +#define AR_PHY_AIC_SRAM_VGA_QUAD_SIGN 0x00000080 +#define AR_PHY_AIC_SRAM_VGA_QUAD_SIGN_S 7 +#define AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB 0x00003F00 +#define AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB_S 8 +#define AR_PHY_AIC_SRAM_VGA_DIR_SIGN 0x00004000 +#define AR_PHY_AIC_SRAM_VGA_DIR_SIGN_S 14 +#define AR_PHY_AIC_SRAM_COM_ATT_6DB 0x00038000 +#define AR_PHY_AIC_SRAM_COM_ATT_6DB_S 15 +#define AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO 0x0000E000 +#define AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO_S 13 +#define AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO 0x00001E00 +#define AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO_S 9 +#define AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING 0x000001F8 +#define AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING_S 3 +#define AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF 0x00000006 +#define AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF_S 1 +#define AR_PHY_AIC_CAL_COM_ATT_DB_FIXED 0x00000001 +#define AR_PHY_AIC_CAL_COM_ATT_DB_FIXED_S 0 + +#endif /* REG_AIC_H */ diff --git a/drivers/net/wireless/ath/ath9k/reg_mci.h b/drivers/net/wireless/ath/ath9k/reg_mci.h new file mode 100644 index 000000000000..6251310704e3 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/reg_mci.h @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef REG_MCI_H +#define REG_MCI_H + +#define AR_MCI_COMMAND0 0x1800 +#define AR_MCI_COMMAND0_HEADER 0xFF +#define AR_MCI_COMMAND0_HEADER_S 0 +#define AR_MCI_COMMAND0_LEN 0x1f00 +#define AR_MCI_COMMAND0_LEN_S 8 +#define AR_MCI_COMMAND0_DISABLE_TIMESTAMP 0x2000 +#define AR_MCI_COMMAND0_DISABLE_TIMESTAMP_S 13 + +#define AR_MCI_COMMAND1 0x1804 + +#define AR_MCI_COMMAND2 0x1808 +#define AR_MCI_COMMAND2_RESET_TX 0x01 +#define AR_MCI_COMMAND2_RESET_TX_S 0 +#define AR_MCI_COMMAND2_RESET_RX 0x02 +#define AR_MCI_COMMAND2_RESET_RX_S 1 +#define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES 0x3FC +#define AR_MCI_COMMAND2_RESET_RX_NUM_CYCLES_S 2 +#define AR_MCI_COMMAND2_RESET_REQ_WAKEUP 0x400 +#define AR_MCI_COMMAND2_RESET_REQ_WAKEUP_S 10 + +#define AR_MCI_RX_CTRL 0x180c + +#define AR_MCI_TX_CTRL 0x1810 +/* + * 0 = no division, + * 1 = divide by 2, + * 2 = divide by 4, + * 3 = divide by 8 + */ +#define AR_MCI_TX_CTRL_CLK_DIV 0x03 +#define AR_MCI_TX_CTRL_CLK_DIV_S 0 +#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE 0x04 +#define AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE_S 2 +#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ 0xFFFFF8 +#define AR_MCI_TX_CTRL_GAIN_UPDATE_FREQ_S 3 +#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM 0xF000000 +#define AR_MCI_TX_CTRL_GAIN_UPDATE_NUM_S 24 + +#define AR_MCI_MSG_ATTRIBUTES_TABLE 0x1814 +#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM 0xFFFF +#define AR_MCI_MSG_ATTRIBUTES_TABLE_CHECKSUM_S 0 +#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR 0xFFFF0000 +#define AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR_S 16 + +#define AR_MCI_SCHD_TABLE_0 0x1818 +#define AR_MCI_SCHD_TABLE_1 0x181c +#define AR_MCI_GPM_0 0x1820 +#define AR_MCI_GPM_1 0x1824 +#define AR_MCI_GPM_WRITE_PTR 0xFFFF0000 +#define AR_MCI_GPM_WRITE_PTR_S 16 +#define AR_MCI_GPM_BUF_LEN 0x0000FFFF +#define AR_MCI_GPM_BUF_LEN_S 0 + +#define AR_MCI_INTERRUPT_RAW 0x1828 + +#define AR_MCI_INTERRUPT_EN 0x182c +#define AR_MCI_INTERRUPT_SW_MSG_DONE 0x00000001 +#define AR_MCI_INTERRUPT_SW_MSG_DONE_S 0 +#define AR_MCI_INTERRUPT_CPU_INT_MSG 0x00000002 +#define AR_MCI_INTERRUPT_CPU_INT_MSG_S 1 +#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL 0x00000004 +#define AR_MCI_INTERRUPT_RX_CKSUM_FAIL_S 2 +#define AR_MCI_INTERRUPT_RX_INVALID_HDR 0x00000008 +#define AR_MCI_INTERRUPT_RX_INVALID_HDR_S 3 +#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL 0x00000010 +#define AR_MCI_INTERRUPT_RX_HW_MSG_FAIL_S 4 +#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL 0x00000020 +#define AR_MCI_INTERRUPT_RX_SW_MSG_FAIL_S 5 +#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL 0x00000080 +#define AR_MCI_INTERRUPT_TX_HW_MSG_FAIL_S 7 +#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL 0x00000100 +#define AR_MCI_INTERRUPT_TX_SW_MSG_FAIL_S 8 +#define AR_MCI_INTERRUPT_RX_MSG 0x00000200 +#define AR_MCI_INTERRUPT_RX_MSG_S 9 +#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE 0x00000400 +#define AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE_S 10 +#define AR_MCI_INTERRUPT_BT_PRI 0x07fff800 +#define AR_MCI_INTERRUPT_BT_PRI_S 11 +#define AR_MCI_INTERRUPT_BT_PRI_THRESH 0x08000000 +#define AR_MCI_INTERRUPT_BT_PRI_THRESH_S 27 +#define AR_MCI_INTERRUPT_BT_FREQ 0x10000000 +#define AR_MCI_INTERRUPT_BT_FREQ_S 28 +#define AR_MCI_INTERRUPT_BT_STOMP 0x20000000 +#define AR_MCI_INTERRUPT_BT_STOMP_S 29 +#define AR_MCI_INTERRUPT_BB_AIC_IRQ 0x40000000 +#define AR_MCI_INTERRUPT_BB_AIC_IRQ_S 30 +#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT 0x80000000 +#define AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT_S 31 + +#define AR_MCI_REMOTE_CPU_INT 0x1830 +#define AR_MCI_REMOTE_CPU_INT_EN 0x1834 +#define AR_MCI_INTERRUPT_RX_MSG_RAW 0x1838 +#define AR_MCI_INTERRUPT_RX_MSG_EN 0x183c +#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET 0x00000001 +#define AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET_S 0 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL 0x00000002 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL_S 1 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK 0x00000004 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_NACK_S 2 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO 0x00000008 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_INFO_S 3 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST 0x00000010 +#define AR_MCI_INTERRUPT_RX_MSG_CONT_RST_S 4 +#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO 0x00000020 +#define AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO_S 5 +#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT 0x00000040 +#define AR_MCI_INTERRUPT_RX_MSG_CPU_INT_S 6 +#define AR_MCI_INTERRUPT_RX_MSG_GPM 0x00000100 +#define AR_MCI_INTERRUPT_RX_MSG_GPM_S 8 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO 0x00000200 +#define AR_MCI_INTERRUPT_RX_MSG_LNA_INFO_S 9 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING 0x00000400 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING_S 10 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING 0x00000800 +#define AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING_S 11 +#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE 0x00001000 +#define AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE_S 12 + +#define AR_MCI_CPU_INT 0x1840 + +#define AR_MCI_RX_STATUS 0x1844 +#define AR_MCI_RX_LAST_SCHD_MSG_INDEX 0x00000F00 +#define AR_MCI_RX_LAST_SCHD_MSG_INDEX_S 8 +#define AR_MCI_RX_REMOTE_SLEEP 0x00001000 +#define AR_MCI_RX_REMOTE_SLEEP_S 12 +#define AR_MCI_RX_MCI_CLK_REQ 0x00002000 +#define AR_MCI_RX_MCI_CLK_REQ_S 13 + +#define AR_MCI_CONT_STATUS 0x1848 +#define AR_MCI_CONT_RSSI_POWER 0x000000FF +#define AR_MCI_CONT_RSSI_POWER_S 0 +#define AR_MCI_CONT_PRIORITY 0x0000FF00 +#define AR_MCI_CONT_PRIORITY_S 8 +#define AR_MCI_CONT_TXRX 0x00010000 +#define AR_MCI_CONT_TXRX_S 16 + +#define AR_MCI_BT_PRI0 0x184c +#define AR_MCI_BT_PRI1 0x1850 +#define AR_MCI_BT_PRI2 0x1854 +#define AR_MCI_BT_PRI3 0x1858 +#define AR_MCI_BT_PRI 0x185c +#define AR_MCI_WL_FREQ0 0x1860 +#define AR_MCI_WL_FREQ1 0x1864 +#define AR_MCI_WL_FREQ2 0x1868 +#define AR_MCI_GAIN 0x186c +#define AR_MCI_WBTIMER1 0x1870 +#define AR_MCI_WBTIMER2 0x1874 +#define AR_MCI_WBTIMER3 0x1878 +#define AR_MCI_WBTIMER4 0x187c +#define AR_MCI_MAXGAIN 0x1880 +#define AR_MCI_HW_SCHD_TBL_CTL 0x1884 +#define AR_MCI_HW_SCHD_TBL_D0 0x1888 +#define AR_MCI_HW_SCHD_TBL_D1 0x188c +#define AR_MCI_HW_SCHD_TBL_D2 0x1890 +#define AR_MCI_HW_SCHD_TBL_D3 0x1894 +#define AR_MCI_TX_PAYLOAD0 0x1898 +#define AR_MCI_TX_PAYLOAD1 0x189c +#define AR_MCI_TX_PAYLOAD2 0x18a0 +#define AR_MCI_TX_PAYLOAD3 0x18a4 +#define AR_BTCOEX_WBTIMER 0x18a8 + +#define AR_BTCOEX_CTRL 0x18ac +#define AR_BTCOEX_CTRL_AR9462_MODE 0x00000001 +#define AR_BTCOEX_CTRL_AR9462_MODE_S 0 +#define AR_BTCOEX_CTRL_WBTIMER_EN 0x00000002 +#define AR_BTCOEX_CTRL_WBTIMER_EN_S 1 +#define AR_BTCOEX_CTRL_MCI_MODE_EN 0x00000004 +#define AR_BTCOEX_CTRL_MCI_MODE_EN_S 2 +#define AR_BTCOEX_CTRL_LNA_SHARED 0x00000008 +#define AR_BTCOEX_CTRL_LNA_SHARED_S 3 +#define AR_BTCOEX_CTRL_PA_SHARED 0x00000010 +#define AR_BTCOEX_CTRL_PA_SHARED_S 4 +#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN 0x00000020 +#define AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN_S 5 +#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN 0x00000040 +#define AR_BTCOEX_CTRL_TIME_TO_NEXT_BT_THRESH_EN_S 6 +#define AR_BTCOEX_CTRL_NUM_ANTENNAS 0x00000180 +#define AR_BTCOEX_CTRL_NUM_ANTENNAS_S 7 +#define AR_BTCOEX_CTRL_RX_CHAIN_MASK 0x00000E00 +#define AR_BTCOEX_CTRL_RX_CHAIN_MASK_S 9 +#define AR_BTCOEX_CTRL_AGGR_THRESH 0x00007000 +#define AR_BTCOEX_CTRL_AGGR_THRESH_S 12 +#define AR_BTCOEX_CTRL_1_CHAIN_BCN 0x00080000 +#define AR_BTCOEX_CTRL_1_CHAIN_BCN_S 19 +#define AR_BTCOEX_CTRL_1_CHAIN_ACK 0x00100000 +#define AR_BTCOEX_CTRL_1_CHAIN_ACK_S 20 +#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN 0x1FE00000 +#define AR_BTCOEX_CTRL_WAIT_BA_MARGIN_S 28 +#define AR_BTCOEX_CTRL_REDUCE_TXPWR 0x20000000 +#define AR_BTCOEX_CTRL_REDUCE_TXPWR_S 29 +#define AR_BTCOEX_CTRL_SPDT_ENABLE_10 0x40000000 +#define AR_BTCOEX_CTRL_SPDT_ENABLE_10_S 30 +#define AR_BTCOEX_CTRL_SPDT_POLARITY 0x80000000 +#define AR_BTCOEX_CTRL_SPDT_POLARITY_S 31 + +#define AR_BTCOEX_WL_WEIGHTS0 0x18b0 +#define AR_BTCOEX_WL_WEIGHTS1 0x18b4 +#define AR_BTCOEX_WL_WEIGHTS2 0x18b8 +#define AR_BTCOEX_WL_WEIGHTS3 0x18bc + +#define AR_BTCOEX_MAX_TXPWR(_x) (0x18c0 + ((_x) << 2)) +#define AR_BTCOEX_WL_LNA 0x1940 +#define AR_BTCOEX_RFGAIN_CTRL 0x1944 +#define AR_BTCOEX_WL_LNA_TIMEOUT 0x003FFFFF +#define AR_BTCOEX_WL_LNA_TIMEOUT_S 0 + +#define AR_BTCOEX_CTRL2 0x1948 +#define AR_BTCOEX_CTRL2_TXPWR_THRESH 0x0007F800 +#define AR_BTCOEX_CTRL2_TXPWR_THRESH_S 11 +#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK 0x00380000 +#define AR_BTCOEX_CTRL2_TX_CHAIN_MASK_S 19 +#define AR_BTCOEX_CTRL2_RX_DEWEIGHT 0x00400000 +#define AR_BTCOEX_CTRL2_RX_DEWEIGHT_S 22 +#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL 0x00800000 +#define AR_BTCOEX_CTRL2_GPIO_OBS_SEL_S 23 +#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL 0x01000000 +#define AR_BTCOEX_CTRL2_MAC_BB_OBS_SEL_S 24 +#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE 0x02000000 +#define AR_BTCOEX_CTRL2_DESC_BASED_TXPWR_ENABLE_S 25 + +#define AR_BTCOEX_CTRL_SPDT_ENABLE 0x00000001 +#define AR_BTCOEX_CTRL_SPDT_ENABLE_S 0 +#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL 0x00000002 +#define AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL_S 1 +#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT 0x00000004 +#define AR_BTCOEX_CTRL_USE_LATCHED_BT_ANT_S 2 +#define AR_GLB_WLAN_UART_INTF_EN 0x00020000 +#define AR_GLB_WLAN_UART_INTF_EN_S 17 +#define AR_GLB_DS_JTAG_DISABLE 0x00040000 +#define AR_GLB_DS_JTAG_DISABLE_S 18 + +#define AR_BTCOEX_RC 0x194c +#define AR_BTCOEX_MAX_RFGAIN(_x) (0x1950 + ((_x) << 2)) +#define AR_BTCOEX_DBG 0x1a50 +#define AR_MCI_LAST_HW_MSG_HDR 0x1a54 +#define AR_MCI_LAST_HW_MSG_BDY 0x1a58 + +#define AR_MCI_SCHD_TABLE_2 0x1a5c +#define AR_MCI_SCHD_TABLE_2_MEM_BASED 0x00000001 +#define AR_MCI_SCHD_TABLE_2_MEM_BASED_S 0 +#define AR_MCI_SCHD_TABLE_2_HW_BASED 0x00000002 +#define AR_MCI_SCHD_TABLE_2_HW_BASED_S 1 + +#define AR_BTCOEX_CTRL3 0x1a60 +#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT 0x00000fff +#define AR_BTCOEX_CTRL3_CONT_INFO_TIMEOUT_S 0 + +#define AR_GLB_SWREG_DISCONT_MODE 0x2002c +#define AR_GLB_SWREG_DISCONT_EN_BT_WLAN 0x3 + +#define AR_MCI_MISC 0x1a74 +#define AR_MCI_MISC_HW_FIX_EN 0x00000001 +#define AR_MCI_MISC_HW_FIX_EN_S 0 + +#define AR_MCI_DBG_CNT_CTRL 0x1a78 +#define AR_MCI_DBG_CNT_CTRL_ENABLE 0x00000001 +#define AR_MCI_DBG_CNT_CTRL_ENABLE_S 0 +#define AR_MCI_DBG_CNT_CTRL_BT_LINKID 0x000007f8 +#define AR_MCI_DBG_CNT_CTRL_BT_LINKID_S 3 + +#define MCI_STAT_ALL_BT_LINKID 0xffff + +#define AR_MCI_INTERRUPT_DEFAULT (AR_MCI_INTERRUPT_SW_MSG_DONE | \ + AR_MCI_INTERRUPT_RX_INVALID_HDR | \ + AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \ + AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \ + AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \ + AR_MCI_INTERRUPT_TX_SW_MSG_FAIL | \ + AR_MCI_INTERRUPT_RX_MSG | \ + AR_MCI_INTERRUPT_REMOTE_SLEEP_UPDATE | \ + AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT) + +#define AR_MCI_INTERRUPT_MSG_FAIL_MASK (AR_MCI_INTERRUPT_RX_HW_MSG_FAIL | \ + AR_MCI_INTERRUPT_RX_SW_MSG_FAIL | \ + AR_MCI_INTERRUPT_TX_HW_MSG_FAIL | \ + AR_MCI_INTERRUPT_TX_SW_MSG_FAIL) + +#define AR_MCI_INTERRUPT_RX_HW_MSG_MASK (AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \ + AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL | \ + AR_MCI_INTERRUPT_RX_MSG_LNA_INFO | \ + AR_MCI_INTERRUPT_RX_MSG_CONT_NACK | \ + AR_MCI_INTERRUPT_RX_MSG_CONT_INFO | \ + AR_MCI_INTERRUPT_RX_MSG_CONT_RST) + +#define AR_MCI_INTERRUPT_RX_MSG_DEFAULT (AR_MCI_INTERRUPT_RX_MSG_GPM | \ + AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | \ + AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING | \ + AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING | \ + AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) + +#endif /* REG_MCI_H */ diff --git a/drivers/net/wireless/ath/ath9k/reg_wow.h b/drivers/net/wireless/ath/ath9k/reg_wow.h new file mode 100644 index 000000000000..453054078cc4 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/reg_wow.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef REG_WOW_H +#define REG_WOW_H + +#define AR_WOW_PATTERN 0x825C +#define AR_WOW_COUNT 0x8260 +#define AR_WOW_BCN_EN 0x8270 +#define AR_WOW_BCN_TIMO 0x8274 +#define AR_WOW_KEEP_ALIVE_TIMO 0x8278 +#define AR_WOW_KEEP_ALIVE 0x827c +#define AR_WOW_KEEP_ALIVE_DELAY 0x8288 +#define AR_WOW_PATTERN_MATCH 0x828c + +/* + * AR_WOW_LENGTH1 + * bit 31:24 pattern 0 length + * bit 23:16 pattern 1 length + * bit 15:8 pattern 2 length + * bit 7:0 pattern 3 length + * + * AR_WOW_LENGTH2 + * bit 31:24 pattern 4 length + * bit 23:16 pattern 5 length + * bit 15:8 pattern 6 length + * bit 7:0 pattern 7 length + * + * AR_WOW_LENGTH3 + * bit 31:24 pattern 8 length + * bit 23:16 pattern 9 length + * bit 15:8 pattern 10 length + * bit 7:0 pattern 11 length + * + * AR_WOW_LENGTH4 + * bit 31:24 pattern 12 length + * bit 23:16 pattern 13 length + * bit 15:8 pattern 14 length + * bit 7:0 pattern 15 length + */ +#define AR_WOW_LENGTH1 0x8360 +#define AR_WOW_LENGTH2 0X8364 +#define AR_WOW_LENGTH3 0X8380 +#define AR_WOW_LENGTH4 0X8384 + +#define AR_WOW_PATTERN_MATCH_LT_256B 0x8368 +#define AR_MAC_PCU_WOW4 0x8370 + +#define AR_SW_WOW_CONTROL 0x20018 +#define AR_SW_WOW_ENABLE 0x1 +#define AR_SWITCH_TO_REFCLK 0x2 +#define AR_RESET_CONTROL 0x4 +#define AR_RESET_VALUE_MASK 0x8 +#define AR_HW_WOW_DISABLE 0x10 +#define AR_CLR_MAC_INTERRUPT 0x20 +#define AR_CLR_KA_INTERRUPT 0x40 + +#define AR_WOW_BACK_OFF_SHIFT(x) ((x & 0xf) << 27) /* in usecs */ +#define AR_WOW_MAC_INTR_EN 0x00040000 +#define AR_WOW_MAGIC_EN 0x00010000 +#define AR_WOW_PATTERN_EN(x) (x & 0xff) +#define AR_WOW_PAT_FOUND_SHIFT 8 +#define AR_WOW_PATTERN_FOUND(x) (x & (0xff << AR_WOW_PAT_FOUND_SHIFT)) +#define AR_WOW_PATTERN_FOUND_MASK ((0xff) << AR_WOW_PAT_FOUND_SHIFT) +#define AR_WOW_MAGIC_PAT_FOUND 0x00020000 +#define AR_WOW_MAC_INTR 0x00080000 +#define AR_WOW_KEEP_ALIVE_FAIL 0x00100000 +#define AR_WOW_BEACON_FAIL 0x00200000 + +#define AR_WOW_STATUS(x) (x & (AR_WOW_PATTERN_FOUND_MASK | \ + AR_WOW_MAGIC_PAT_FOUND | \ + AR_WOW_KEEP_ALIVE_FAIL | \ + AR_WOW_BEACON_FAIL)) +#define AR_WOW_CLEAR_EVENTS(x) (x & ~(AR_WOW_PATTERN_EN(0xff) | \ + AR_WOW_MAGIC_EN | \ + AR_WOW_MAC_INTR_EN | \ + AR_WOW_BEACON_FAIL | \ + AR_WOW_KEEP_ALIVE_FAIL)) + +#define AR_WOW2_PATTERN_EN(x) ((x & 0xff) << 0) +#define AR_WOW2_PATTERN_FOUND_SHIFT 8 +#define AR_WOW2_PATTERN_FOUND(x) (x & (0xff << AR_WOW2_PATTERN_FOUND_SHIFT)) +#define AR_WOW2_PATTERN_FOUND_MASK ((0xff) << AR_WOW2_PATTERN_FOUND_SHIFT) + +#define AR_WOW_STATUS2(x) (x & AR_WOW2_PATTERN_FOUND_MASK) +#define AR_WOW_CLEAR_EVENTS2(x) (x & ~(AR_WOW2_PATTERN_EN(0xff))) + +#define AR_WOW_AIFS_CNT(x) (x & 0xff) +#define AR_WOW_SLOT_CNT(x) ((x & 0xff) << 8) +#define AR_WOW_KEEP_ALIVE_CNT(x) ((x & 0xff) << 16) + +#define AR_WOW_BEACON_FAIL_EN 0x00000001 +#define AR_WOW_BEACON_TIMO 0x40000000 +#define AR_WOW_KEEP_ALIVE_NEVER 0xffffffff +#define AR_WOW_KEEP_ALIVE_AUTO_DIS 0x00000001 +#define AR_WOW_KEEP_ALIVE_FAIL_DIS 0x00000002 +#define AR_WOW_KEEP_ALIVE_DELAY_VALUE 0x000003e8 /* 1 msec */ +#define AR_WOW_BMISSTHRESHOLD 0x20 +#define AR_WOW_PAT_END_OF_PKT(x) (x & 0xf) +#define AR_WOW_PAT_OFF_MATCH(x) ((x & 0xf) << 8) +#define AR_WOW_PAT_BACKOFF 0x00000004 +#define AR_WOW_CNT_AIFS_CNT 0x00000022 +#define AR_WOW_CNT_SLOT_CNT 0x00000009 +#define AR_WOW_CNT_KA_CNT 0x00000008 + +#define AR_WOW_TRANSMIT_BUFFER 0xe000 +#define AR_WOW_TXBUF(i) (AR_WOW_TRANSMIT_BUFFER + ((i) << 2)) +#define AR_WOW_KA_DESC_WORD2 0xe000 +#define AR_WOW_TB_PATTERN(i) (0xe100 + (i << 8)) +#define AR_WOW_TB_MASK(i) (0xec00 + (i << 5)) +#define AR_WOW_PATTERN_SUPPORTED_LEGACY 0xff +#define AR_WOW_PATTERN_SUPPORTED 0xffff +#define AR_WOW_LENGTH_MAX 0xff +#define AR_WOW_LEN1_SHIFT(_i) ((0x3 - ((_i) & 0x3)) << 0x3) +#define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i)) +#define AR_WOW_LEN2_SHIFT(_i) ((0x7 - ((_i) & 0x7)) << 0x3) +#define AR_WOW_LENGTH2_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN2_SHIFT(_i)) +#define AR_WOW_LEN3_SHIFT(_i) ((0xb - ((_i) & 0xb)) << 0x3) +#define AR_WOW_LENGTH3_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN3_SHIFT(_i)) +#define AR_WOW_LEN4_SHIFT(_i) ((0xf - ((_i) & 0xf)) << 0x3) +#define AR_WOW_LENGTH4_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN4_SHIFT(_i)) + +#endif /* REG_WOW_H */ diff --git a/drivers/net/wireless/ath/ath9k/rng.c b/drivers/net/wireless/ath/ath9k/rng.c new file mode 100644 index 000000000000..e1def77591c6 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/rng.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/hw_random.h> +#include <linux/kthread.h> + +#include "ath9k.h" +#include "hw.h" +#include "ar9003_phy.h" + +static int ath9k_rng_data_read(struct ath_softc *sc, u32 *buf, u32 buf_size) +{ + int i, j; + u32 v1, v2, rng_last = sc->rng_last; + struct ath_hw *ah = sc->sc_ah; + + ath9k_ps_wakeup(sc); + + REG_RMW_FIELD(ah, AR_PHY_TEST(ah), AR_PHY_TEST_BBB_OBS_SEL, 1); + REG_CLR_BIT(ah, AR_PHY_TEST(ah), AR_PHY_TEST_RX_OBS_SEL_BIT5); + REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS(ah), AR_PHY_TEST_CTL_RX_OBS_SEL, 0); + + for (i = 0, j = 0; i < buf_size; i++) { + v1 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff; + v2 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff; + + /* wait for data ready */ + if (v1 && v2 && rng_last != v1 && v1 != v2 && v1 != 0xffff && + v2 != 0xffff) + buf[j++] = (v1 << 16) | v2; + + rng_last = v2; + } + + ath9k_ps_restore(sc); + + sc->rng_last = rng_last; + + return j << 2; +} + +static u32 ath9k_rng_delay_get(u32 fail_stats) +{ + u32 delay; + + if (fail_stats < 100) + delay = 10; + else if (fail_stats < 105) + delay = 1000; + else + delay = 10000; + + return delay; +} + +static int ath9k_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait) +{ + struct ath_softc *sc = container_of(rng, struct ath_softc, rng_ops); + u32 fail_stats = 0, word; + int bytes_read = 0; + + for (;;) { + if (max & ~3UL) + bytes_read = ath9k_rng_data_read(sc, buf, max >> 2); + if ((max & 3UL) && ath9k_rng_data_read(sc, &word, 1)) { + memcpy(buf + bytes_read, &word, max & 3UL); + bytes_read += max & 3UL; + memzero_explicit(&word, sizeof(word)); + } + if (!wait || !max || likely(bytes_read) || fail_stats > 110) + break; + + if (hwrng_msleep(rng, ath9k_rng_delay_get(++fail_stats))) + break; + } + + if (wait && !bytes_read && max) + bytes_read = -EIO; + return bytes_read; +} + +void ath9k_rng_start(struct ath_softc *sc) +{ + static atomic_t serial = ATOMIC_INIT(0); + struct ath_hw *ah = sc->sc_ah; + + if (sc->rng_ops.read) + return; + + if (!AR_SREV_9300_20_OR_LATER(ah)) + return; + + snprintf(sc->rng_name, sizeof(sc->rng_name), "ath9k_%u", + (atomic_inc_return(&serial) - 1) & U16_MAX); + sc->rng_ops.name = sc->rng_name; + sc->rng_ops.read = ath9k_rng_read; + sc->rng_ops.quality = 320; + + if (devm_hwrng_register(sc->dev, &sc->rng_ops)) + sc->rng_ops.read = NULL; +} + +void ath9k_rng_stop(struct ath_softc *sc) +{ + if (sc->rng_ops.read) { + devm_hwrng_unregister(sc->dev, &sc->rng_ops); + sc->rng_ops.read = NULL; + } +} diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c new file mode 100644 index 000000000000..f2144fd39093 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2013 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ath9k.h" + +static void ath9k_tx99_stop(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + + ath_drain_all_txq(sc); + ath_startrecv(sc); + + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); + + ieee80211_wake_queues(sc->hw); + + kfree_skb(sc->tx99_skb); + sc->tx99_skb = NULL; + sc->tx99_state = false; + + ath9k_hw_tx99_stop(sc->sc_ah); + ath_dbg(common, XMIT, "TX99 stopped\n"); +} + +static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) +{ + static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24, + 0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50, + 0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1, + 0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18, + 0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8, + 0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84, + 0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3, + 0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0}; + u32 len = 1200; + struct ieee80211_tx_rate *rate; + struct ieee80211_hw *hw = sc->hw; + struct ath_hw *ah = sc->sc_ah; + struct ieee80211_hdr *hdr; + struct ieee80211_tx_info *tx_info; + struct sk_buff *skb; + struct ath_vif *avp; + + skb = alloc_skb(len, GFP_KERNEL); + if (!skb) + return NULL; + + skb_put(skb, len); + + memset(skb->data, 0, len); + + hdr = (struct ieee80211_hdr *)skb->data; + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA); + hdr->duration_id = 0; + + memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN); + memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); + memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); + + if (sc->tx99_vif) { + avp = (struct ath_vif *) sc->tx99_vif->drv_priv; + hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); + } + + tx_info = IEEE80211_SKB_CB(skb); + memset(tx_info, 0, sizeof(*tx_info)); + rate = &tx_info->control.rates[0]; + tx_info->band = sc->cur_chan->chandef.chan->band; + tx_info->flags = IEEE80211_TX_CTL_NO_ACK; + tx_info->control.vif = sc->tx99_vif; + rate->count = 1; + if (ah->curchan && IS_CHAN_HT(ah->curchan)) { + rate->flags |= IEEE80211_TX_RC_MCS; + if (IS_CHAN_HT40(ah->curchan)) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + } + + memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data)); + + return skb; +} + +static void ath9k_tx99_deinit(struct ath_softc *sc) +{ + ath_reset(sc, NULL); + + ath9k_ps_wakeup(sc); + ath9k_tx99_stop(sc); + ath9k_ps_restore(sc); +} + +static int ath9k_tx99_init(struct ath_softc *sc) +{ + struct ieee80211_hw *hw = sc->hw; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_tx_control txctl; + int r; + + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { + ath_err(common, + "driver is in invalid state unable to use TX99"); + return -EINVAL; + } + + sc->tx99_skb = ath9k_build_tx99_skb(sc); + if (!sc->tx99_skb) + return -ENOMEM; + + memset(&txctl, 0, sizeof(txctl)); + txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; + + ath_reset(sc, NULL); + + ath9k_ps_wakeup(sc); + + ath9k_hw_disable_interrupts(ah); + ath_drain_all_txq(sc); + ath_stoprecv(sc); + + sc->tx99_state = true; + + ieee80211_stop_queues(hw); + + if (sc->tx99_power == MAX_RATE_POWER + 1) + sc->tx99_power = MAX_RATE_POWER; + + ath9k_hw_tx99_set_txpower(ah, sc->tx99_power); + r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl); + if (r) { + ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n"); + return r; + } + + ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n", + sc->tx99_power, + sc->tx99_power / 2); + + /* We leave the hardware awake as it will be chugging on */ + + return 0; +} + +static ssize_t read_file_tx99(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[3]; + unsigned int len; + + len = sprintf(buf, "%d\n", sc->tx99_state); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_tx99(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + bool start; + ssize_t ret; + int r; + + if (count < 1) + return -EINVAL; + + if (sc->cur_chan->nvifs > 1) + return -EOPNOTSUPP; + + ret = kstrtobool_from_user(user_buf, count, &start); + if (ret) + return ret; + + mutex_lock(&sc->mutex); + + if (start == sc->tx99_state) { + if (!start) + goto out; + ath_dbg(common, XMIT, "Resetting TX99\n"); + ath9k_tx99_deinit(sc); + } + + if (!start) { + ath9k_tx99_deinit(sc); + goto out; + } + + r = ath9k_tx99_init(sc); + if (r) { + mutex_unlock(&sc->mutex); + return r; + } +out: + mutex_unlock(&sc->mutex); + return count; +} + +static const struct file_operations fops_tx99 = { + .read = read_file_tx99, + .write = write_file_tx99, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_tx99_power(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[32]; + unsigned int len; + + len = sprintf(buf, "%d (%d dBm)\n", + sc->tx99_power, + sc->tx99_power / 2); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_tx99_power(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + int r; + u8 tx_power; + + r = kstrtou8_from_user(user_buf, count, 0, &tx_power); + if (r) + return r; + + if (tx_power > MAX_RATE_POWER) + return -EINVAL; + + sc->tx99_power = tx_power; + + ath9k_ps_wakeup(sc); + ath9k_hw_tx99_set_txpower(sc->sc_ah, sc->tx99_power); + ath9k_ps_restore(sc); + + return count; +} + +static const struct file_operations fops_tx99_power = { + .read = read_file_tx99_power, + .write = write_file_tx99_power, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_tx99_init_debug(struct ath_softc *sc) +{ + if (!AR_SREV_9280_20_OR_LATER(sc->sc_ah)) + return; + + debugfs_create_file("tx99", 0600, + sc->debug.debugfs_phy, sc, + &fops_tx99); + debugfs_create_file("tx99_power", 0600, + sc->debug.debugfs_phy, sc, + &fops_tx99_power); +} diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 65c8894c5f81..805ad31edba2 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -61,6 +61,8 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_REG_READ_CMDID"; case WMI_REG_WRITE_CMDID: return "WMI_REG_WRITE_CMDID"; + case WMI_REG_RMW_CMDID: + return "WMI_REG_RMW_CMDID"; case WMI_RC_STATE_CHANGE_CMDID: return "WMI_RC_STATE_CHANGE_CMDID"; case WMI_RC_RATE_UPDATE_CMDID: @@ -101,22 +103,25 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv) spin_lock_init(&wmi->event_lock); mutex_init(&wmi->op_mutex); mutex_init(&wmi->multi_write_mutex); + mutex_init(&wmi->multi_rmw_mutex); init_completion(&wmi->cmd_wait); INIT_LIST_HEAD(&wmi->pending_tx_events); - tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet, - (unsigned long)wmi); + tasklet_setup(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet); return wmi; } -void ath9k_deinit_wmi(struct ath9k_htc_priv *priv) +void ath9k_stop_wmi(struct ath9k_htc_priv *priv) { struct wmi *wmi = priv->wmi; mutex_lock(&wmi->op_mutex); wmi->stopped = true; mutex_unlock(&wmi->op_mutex); +} +void ath9k_destroy_wmi(struct ath9k_htc_priv *priv) +{ kfree(priv->wmi); } @@ -130,9 +135,9 @@ void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv) spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags); } -void ath9k_wmi_event_tasklet(unsigned long data) +void ath9k_wmi_event_tasklet(struct tasklet_struct *t) { - struct wmi *wmi = (struct wmi *)data; + struct wmi *wmi = from_tasklet(wmi, t, wmi_event_tasklet); struct ath9k_htc_priv *priv = wmi->drv_priv; struct wmi_cmd_hdr *hdr; void *wmi_event; @@ -150,13 +155,19 @@ void ath9k_wmi_event_tasklet(unsigned long data) } spin_unlock_irqrestore(&wmi->wmi_lock, flags); + /* Check if ath9k_htc_probe_device() completed. */ + if (!data_race(priv->initialized)) { + kfree_skb(skb); + continue; + } + hdr = (struct wmi_cmd_hdr *) skb->data; cmd_id = be16_to_cpu(hdr->command_id); wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); switch (cmd_id) { case WMI_SWBA_EVENTID: - swba = (struct wmi_event_swba *) wmi_event; + swba = wmi_event; ath9k_htc_swba(priv, swba); break; case WMI_FATAL_EVENTID: @@ -204,34 +215,39 @@ static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb) static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, enum htc_endpoint_id epid) { - struct wmi *wmi = (struct wmi *) priv; + struct wmi *wmi = priv; struct wmi_cmd_hdr *hdr; + unsigned long flags; u16 cmd_id; if (unlikely(wmi->stopped)) goto free_skb; + /* Validate the obtained SKB. */ + if (unlikely(skb->len < sizeof(struct wmi_cmd_hdr))) + goto free_skb; + hdr = (struct wmi_cmd_hdr *) skb->data; cmd_id = be16_to_cpu(hdr->command_id); if (cmd_id & 0x1000) { - spin_lock(&wmi->wmi_lock); + spin_lock_irqsave(&wmi->wmi_lock, flags); __skb_queue_tail(&wmi->wmi_event_queue, skb); - spin_unlock(&wmi->wmi_lock); + spin_unlock_irqrestore(&wmi->wmi_lock, flags); tasklet_schedule(&wmi->wmi_event_tasklet); return; } /* Check if there has been a timeout. */ - spin_lock(&wmi->wmi_lock); - if (cmd_id != wmi->last_cmd_id) { - spin_unlock(&wmi->wmi_lock); + spin_lock_irqsave(&wmi->wmi_lock, flags); + if (be16_to_cpu(hdr->seq_no) != wmi->last_seq_id) { + spin_unlock_irqrestore(&wmi->wmi_lock, flags); goto free_skb; } - spin_unlock(&wmi->wmi_lock); /* WMI command response */ ath9k_wmi_rsp_callback(wmi, skb); + spin_unlock_irqrestore(&wmi->wmi_lock, flags); free_skb: kfree_skb(skb); @@ -269,14 +285,25 @@ int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi, static int ath9k_wmi_cmd_issue(struct wmi *wmi, struct sk_buff *skb, - enum wmi_cmd_id cmd, u16 len) + enum wmi_cmd_id cmd, u16 len, + u8 *rsp_buf, u32 rsp_len) { struct wmi_cmd_hdr *hdr; + unsigned long flags; - hdr = (struct wmi_cmd_hdr *) skb_push(skb, sizeof(struct wmi_cmd_hdr)); + hdr = skb_push(skb, sizeof(struct wmi_cmd_hdr)); hdr->command_id = cpu_to_be16(cmd); hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id); + spin_lock_irqsave(&wmi->wmi_lock, flags); + + /* record the rsp buffer and length */ + wmi->cmd_rsp_buf = rsp_buf; + wmi->cmd_rsp_len = rsp_len; + + wmi->last_seq_id = wmi->tx_seq_id; + spin_unlock_irqrestore(&wmi->wmi_lock, flags); + return htc_send_epid(wmi->htc, skb, wmi->ctrl_epid); } @@ -289,10 +316,9 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, struct ath_common *common = ath9k_hw_common(ah); u16 headroom = sizeof(struct htc_frame_hdr) + sizeof(struct wmi_cmd_hdr); + unsigned long time_left, flags; struct sk_buff *skb; - u8 *data; - int time_left, ret = 0; - unsigned long flags; + int ret = 0; if (ah->ah_flags & AH_UNPLUGGED) return 0; @@ -304,8 +330,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, skb_reserve(skb, headroom); if (cmd_len != 0 && cmd_buf != NULL) { - data = (u8 *) skb_put(skb, cmd_len); - memcpy(data, cmd_buf, cmd_len); + skb_put_data(skb, cmd_buf, cmd_len); } mutex_lock(&wmi->op_mutex); @@ -316,15 +341,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, goto out; } - /* record the rsp buffer and length */ - wmi->cmd_rsp_buf = rsp_buf; - wmi->cmd_rsp_len = rsp_len; - - spin_lock_irqsave(&wmi->wmi_lock, flags); - wmi->last_cmd_id = cmd_id; - spin_unlock_irqrestore(&wmi->wmi_lock, flags); - - ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len); + ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len, rsp_buf, rsp_len); if (ret) goto out; @@ -332,6 +349,9 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, if (!time_left) { ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n", wmi_cmd_to_name(cmd_id)); + spin_lock_irqsave(&wmi->wmi_lock, flags); + wmi->last_seq_id = 0; + spin_unlock_irqrestore(&wmi->wmi_lock, flags); mutex_unlock(&wmi->op_mutex); return -ETIMEDOUT; } diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index fde6da619f30..5c3b710b8f31 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -39,7 +39,7 @@ struct wmi_fw_version { struct wmi_event_swba { __be64 tsf; u8 beacon_pending; -}; +} __packed; /* * 64 - HTC header - WMI header - 1 / txstatus @@ -112,6 +112,7 @@ enum wmi_cmd_id { WMI_TX_STATS_CMDID, WMI_RX_STATS_CMDID, WMI_BITRATE_MASK_CMDID, + WMI_REG_RMW_CMDID, }; enum wmi_event_id { @@ -125,12 +126,19 @@ enum wmi_event_id { }; #define MAX_CMD_NUMBER 62 +#define MAX_RMW_CMD_NUMBER 15 struct register_write { __be32 reg; __be32 val; }; +struct register_rmw { + __be32 reg; + __be32 set; + __be32 clr; +} __packed; + struct ath9k_htc_tx_event { int count; struct __wmi_event_txstatus txs; @@ -143,7 +151,7 @@ struct wmi { enum htc_endpoint_id ctrl_epid; struct mutex op_mutex; struct completion cmd_wait; - enum wmi_cmd_id last_cmd_id; + u16 last_seq_id; struct sk_buff_head wmi_event_queue; struct tasklet_struct wmi_event_tasklet; u16 tx_seq_id; @@ -156,23 +164,32 @@ struct wmi { spinlock_t wmi_lock; + /* multi write section */ atomic_t mwrite_cnt; struct register_write multi_write[MAX_CMD_NUMBER]; u32 multi_write_idx; struct mutex multi_write_mutex; + + /* multi rmw section */ + atomic_t m_rmw_cnt; + struct register_rmw multi_rmw[MAX_RMW_CMD_NUMBER]; + u32 multi_rmw_idx; + struct mutex multi_rmw_mutex; + }; struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv); -void ath9k_deinit_wmi(struct ath9k_htc_priv *priv); int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi, enum htc_endpoint_id *wmi_ctrl_epid); int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, u8 *cmd_buf, u32 cmd_len, u8 *rsp_buf, u32 rsp_len, u32 timeout); -void ath9k_wmi_event_tasklet(unsigned long data); +void ath9k_wmi_event_tasklet(struct tasklet_struct *t); void ath9k_fatal_work(struct work_struct *work); void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv); +void ath9k_stop_wmi(struct ath9k_htc_priv *priv); +void ath9k_destroy_wmi(struct ath9k_htc_priv *priv); #define WMI_CMD(_wmi_cmd) \ do { \ diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 81c88dd606dc..ed4152cd44f0 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Qualcomm Atheros, Inc. + * Copyright (c) 2013 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -14,409 +14,335 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <linux/export.h> #include "ath9k.h" -#include "reg.h" -#include "hw-ops.h" -const char *ath9k_hw_wow_event_to_string(u32 wow_event) +static const struct wiphy_wowlan_support ath9k_wowlan_support_legacy = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .n_patterns = MAX_NUM_USER_PATTERN, + .pattern_min_len = 1, + .pattern_max_len = MAX_PATTERN_SIZE, +}; + +static const struct wiphy_wowlan_support ath9k_wowlan_support = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .n_patterns = MAX_NUM_PATTERN - 2, + .pattern_min_len = 1, + .pattern_max_len = MAX_PATTERN_SIZE, +}; + +static u8 ath9k_wow_map_triggers(struct ath_softc *sc, + struct cfg80211_wowlan *wowlan) { - if (wow_event & AH_WOW_MAGIC_PATTERN_EN) - return "Magic pattern"; - if (wow_event & AH_WOW_USER_PATTERN_EN) - return "User pattern"; - if (wow_event & AH_WOW_LINK_CHANGE) - return "Link change"; - if (wow_event & AH_WOW_BEACON_MISS) - return "Beacon miss"; - - return "unknown reason"; -} -EXPORT_SYMBOL(ath9k_hw_wow_event_to_string); - -static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) -{ - struct ath_common *common = ath9k_hw_common(ah); - - REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + u8 wow_triggers = 0; - /* set rx disable bit */ - REG_WRITE(ah, AR_CR, AR_CR_RXD); + if (wowlan->disconnect) + wow_triggers |= AH_WOW_LINK_CHANGE | + AH_WOW_BEACON_MISS; + if (wowlan->magic_pkt) + wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; - if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) { - ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", - REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); - return; - } + if (wowlan->n_patterns) + wow_triggers |= AH_WOW_USER_PATTERN_EN; - REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); + return wow_triggers; } -static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) +static int ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) { + struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - u8 sta_mac_addr[ETH_ALEN], ap_mac_addr[ETH_ALEN]; - u32 ctl[13] = {0}; - u32 data_word[KAL_NUM_DATA_WORDS]; - u8 i; - u32 wow_ka_data_word0; - - memcpy(sta_mac_addr, common->macaddr, ETH_ALEN); - memcpy(ap_mac_addr, common->curbssid, ETH_ALEN); - - /* set the transmit buffer */ - ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16)); - ctl[1] = 0; - ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */ - ctl[4] = 0; - ctl[7] = (ah->txchainmask) << 2; - ctl[2] = 0xf << 16; /* tx_tries 0 */ - - for (i = 0; i < KAL_NUM_DESC_WORDS; i++) - REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); - - REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); - - data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) | - (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16); - data_word[1] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | - (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); - data_word[2] = (sta_mac_addr[1] << 24) | (sta_mac_addr[0] << 16) | - (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); - data_word[3] = (sta_mac_addr[5] << 24) | (sta_mac_addr[4] << 16) | - (sta_mac_addr[3] << 8) | (sta_mac_addr[2]); - data_word[4] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | - (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); - data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); - - if (AR_SREV_9462_20(ah)) { - /* AR9462 2.0 has an extra descriptor word (time based - * discard) compared to other chips */ - REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0); - wow_ka_data_word0 = AR_WOW_TXBUF(13); - } else { - wow_ka_data_word0 = AR_WOW_TXBUF(12); - } - - for (i = 0; i < KAL_NUM_DATA_WORDS; i++) - REG_WRITE(ah, (wow_ka_data_word0 + i*4), data_word[i]); + int pattern_count = 0; + int ret, i, byte_cnt = 0; + u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; + u8 dis_deauth_mask[MAX_PATTERN_SIZE]; -} + memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE); + memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE); -void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, - u8 *user_mask, int pattern_count, - int pattern_len) -{ - int i; - u32 pattern_val, mask_val; - u32 set, clr; - - /* FIXME: should check count by querying the hardware capability */ - if (pattern_count >= MAX_NUM_PATTERN) - return; - - REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count)); - - /* set the registers for pattern */ - for (i = 0; i < MAX_PATTERN_SIZE; i += 4) { - memcpy(&pattern_val, user_pattern, 4); - REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i), - pattern_val); - user_pattern += 4; - } - - /* set the registers for mask */ - for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) { - memcpy(&mask_val, user_mask, 4); - REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val); - user_mask += 4; - } - - /* set the pattern length to be matched + /* + * Create Disassociate / Deauthenticate packet filter + * + * 2 bytes 2 byte 6 bytes 6 bytes 6 bytes + * +--------------+----------+---------+--------+--------+---- + * + Frame Control+ Duration + DA + SA + BSSID + + * +--------------+----------+---------+--------+--------+---- * - * AR_WOW_LENGTH1_REG1 - * bit 31:24 pattern 0 length - * bit 23:16 pattern 1 length - * bit 15:8 pattern 2 length - * bit 7:0 pattern 3 length + * The above is the management frame format for disassociate/ + * deauthenticate pattern, from this we need to match the first byte + * of 'Frame Control' and DA, SA, and BSSID fields + * (skipping 2nd byte of FC and Duration field. * - * AR_WOW_LENGTH1_REG2 - * bit 31:24 pattern 4 length - * bit 23:16 pattern 5 length - * bit 15:8 pattern 6 length - * bit 7:0 pattern 7 length + * Disassociate pattern + * -------------------- + * Frame control = 00 00 1010 + * DA, SA, BSSID = x:x:x:x:x:x + * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x + * | x:x:x:x:x:x -- 22 bytes * - * the below logic writes out the new - * pattern length for the corresponding - * pattern_count, while masking out the - * other fields + * Deauthenticate pattern + * ---------------------- + * Frame control = 00 00 1100 + * DA, SA, BSSID = x:x:x:x:x:x + * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x + * | x:x:x:x:x:x -- 22 bytes */ - ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); - - if (pattern_count < 4) { - /* Pattern 0-3 uses AR_WOW_LENGTH1 register */ - set = (pattern_len & AR_WOW_LENGTH_MAX) << - AR_WOW_LEN1_SHIFT(pattern_count); - clr = AR_WOW_LENGTH1_MASK(pattern_count); - REG_RMW(ah, AR_WOW_LENGTH1, set, clr); - } else { - /* Pattern 4-7 uses AR_WOW_LENGTH2 register */ - set = (pattern_len & AR_WOW_LENGTH_MAX) << - AR_WOW_LEN2_SHIFT(pattern_count); - clr = AR_WOW_LENGTH2_MASK(pattern_count); - REG_RMW(ah, AR_WOW_LENGTH2, set, clr); - } + /* Fill out the mask with all FF's */ + for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++) + dis_deauth_mask[i] = 0xff; -} -EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern); + /* copy the first byte of frame control field */ + dis_deauth_pattern[byte_cnt] = 0xa0; + byte_cnt++; -u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) -{ - u32 wow_status = 0; - u32 val = 0, rval; + /* skip 2nd byte of frame control and Duration field */ + byte_cnt += 3; /* - * read the WoW status register to know - * the wakeup reason + * need not match the destination mac address, it can be a broadcast + * mac address or an unicast to this station */ - rval = REG_READ(ah, AR_WOW_PATTERN); - val = AR_WOW_STATUS(rval); + byte_cnt += 6; - /* - * mask only the WoW events that we have enabled. Sometimes - * we have spurious WoW events from the AR_WOW_PATTERN - * register. This mask will clean it up. - */ + /* copy the source mac address */ + memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); - val &= ah->wow_event_mask; - - if (val) { - if (val & AR_WOW_MAGIC_PAT_FOUND) - wow_status |= AH_WOW_MAGIC_PATTERN_EN; - if (AR_WOW_PATTERN_FOUND(val)) - wow_status |= AH_WOW_USER_PATTERN_EN; - if (val & AR_WOW_KEEP_ALIVE_FAIL) - wow_status |= AH_WOW_LINK_CHANGE; - if (val & AR_WOW_BEACON_FAIL) - wow_status |= AH_WOW_BEACON_MISS; - } + byte_cnt += 6; - /* - * set and clear WOW_PME_CLEAR registers for the chip to - * generate next wow signal. - * disable D3 before accessing other registers ? - */ + /* copy the bssid, its same as the source mac address */ + memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); - /* do we need to check the bit value 0x01000000 (7-10) ?? */ - REG_RMW(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR, - AR_PMCTRL_PWR_STATE_D1D3); + /* Create Disassociate pattern mask */ + dis_deauth_mask[0] = 0xfe; + dis_deauth_mask[1] = 0x03; + dis_deauth_mask[2] = 0xc0; - /* - * clear all events - */ - REG_WRITE(ah, AR_WOW_PATTERN, - AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN))); + ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, + pattern_count, byte_cnt); + if (ret) + goto exit; + pattern_count++; /* - * restore the beacon threshold to init value + * for de-authenticate pattern, only the first byte of the frame + * control field gets changed from 0xA0 to 0xC0 */ - REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); + dis_deauth_pattern[0] = 0xC0; - /* - * Restore the way the PCI-E reset, Power-On-Reset, external - * PCIE_POR_SHORT pins are tied to its original value. - * Previously just before WoW sleep, we untie the PCI-E - * reset to our Chip's Power On Reset so that any PCI-E - * reset from the bus will not reset our chip - */ - if (ah->is_pciexpress) - ath9k_hw_configpcipowersave(ah, false); + ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, + pattern_count, byte_cnt); +exit: + return ret; +} - ah->wow_event_mask = 0; +static int ath9k_wow_add_pattern(struct ath_softc *sc, + struct cfg80211_wowlan *wowlan) +{ + struct ath_hw *ah = sc->sc_ah; + struct cfg80211_pkt_pattern *patterns = wowlan->patterns; + u8 wow_pattern[MAX_PATTERN_SIZE]; + u8 wow_mask[MAX_PATTERN_SIZE]; + int mask_len, ret = 0; + s8 i = 0; + + for (i = 0; i < wowlan->n_patterns; i++) { + mask_len = DIV_ROUND_UP(patterns[i].pattern_len, 8); + memset(wow_pattern, 0, MAX_PATTERN_SIZE); + memset(wow_mask, 0, MAX_PATTERN_SIZE); + memcpy(wow_pattern, patterns[i].pattern, patterns[i].pattern_len); + memcpy(wow_mask, patterns[i].mask, mask_len); + + ret = ath9k_hw_wow_apply_pattern(ah, + wow_pattern, + wow_mask, + i + 2, + patterns[i].pattern_len); + if (ret) + break; + } - return wow_status; + return ret; } -EXPORT_SYMBOL(ath9k_hw_wow_wakeup); -void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) +int ath9k_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) { - u32 wow_event_mask; - u32 set, clr; + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + u8 triggers; + int ret = 0; - /* - * wow_event_mask is a mask to the AR_WOW_PATTERN register to - * indicate which WoW events we have enabled. The WoW events - * are from the 'pattern_enable' in this function and - * 'pattern_count' of ath9k_hw_wow_apply_pattern() - */ - wow_event_mask = ah->wow_event_mask; + ath9k_deinit_channel_context(sc); - /* - * Untie Power-on-Reset from the PCI-E-Reset. When we are in - * WOW sleep, we do want the Reset from the PCI-E to disturb - * our hw state - */ - if (ah->is_pciexpress) { - /* - * we need to untie the internal POR (power-on-reset) - * to the external PCI-E reset. We also need to tie - * the PCI-E Phy reset to the PCI-E reset. - */ - set = AR_WA_RESET_EN | AR_WA_POR_SHORT; - clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE; - REG_RMW(ah, AR_WA, set, clr); + mutex_lock(&sc->mutex); + + if (test_bit(ATH_OP_INVALID, &common->op_flags)) { + ath_err(common, "Device not present\n"); + ret = -ENODEV; + goto fail_wow; } - /* - * set the power states appropriately and enable PME - */ - set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA | - AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR; + if (WARN_ON(!wowlan)) { + ath_err(common, "None of the WoW triggers enabled\n"); + ret = -EINVAL; + goto fail_wow; + } - /* - * set and clear WOW_PME_CLEAR registers for the chip - * to generate next wow signal. - */ - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); - clr = AR_PMCTRL_WOW_PME_CLR; - REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); + if (sc->cur_chan->nvifs > 1) { + ath_dbg(common, WOW, "WoW for multivif is not yet supported\n"); + ret = 1; + goto fail_wow; + } - /* - * Setup for: - * - beacon misses - * - magic pattern - * - keep alive timeout - * - pattern matching - */ + if (ath9k_is_chanctx_enabled()) { + if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) { + ath_dbg(common, WOW, + "Multi-channel WOW is not supported\n"); + ret = 1; + goto fail_wow; + } + } - /* - * Program default values for pattern backoff, aifs/slot/KAL count, - * beacon miss timeout, KAL timeout, etc. - */ - set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF); - REG_SET_BIT(ah, AR_WOW_PATTERN, set); + if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) { + ath_dbg(common, WOW, "None of the STA vifs are associated\n"); + ret = 1; + goto fail_wow; + } - set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | - AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | - AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT); - REG_SET_BIT(ah, AR_WOW_COUNT, set); + triggers = ath9k_wow_map_triggers(sc, wowlan); + if (!triggers) { + ath_dbg(common, WOW, "No valid WoW triggers\n"); + ret = 1; + goto fail_wow; + } - if (pattern_enable & AH_WOW_BEACON_MISS) - set = AR_WOW_BEACON_TIMO; - /* We are not using beacon miss, program a large value */ - else - set = AR_WOW_BEACON_TIMO_MAX; + ath_cancel_work(sc); + ath_stop_ani(sc); - REG_WRITE(ah, AR_WOW_BCN_TIMO, set); + ath9k_ps_wakeup(sc); + + ath9k_stop_btcoex(sc); /* - * Keep alive timo in ms except AR9280 + * Enable wake up on receiving disassoc/deauth + * frame by default. */ - if (!pattern_enable) - set = AR_WOW_KEEP_ALIVE_NEVER; - else - set = KAL_TIMEOUT * 32; + ret = ath9k_wow_add_disassoc_deauth_pattern(sc); + if (ret) { + ath_err(common, + "Unable to add disassoc/deauth pattern: %d\n", ret); + goto fail_wow; + } - REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set); + if (triggers & AH_WOW_USER_PATTERN_EN) { + ret = ath9k_wow_add_pattern(sc, wowlan); + if (ret) { + ath_err(common, + "Unable to add user pattern: %d\n", ret); + goto fail_wow; + } + } + spin_lock_bh(&sc->sc_pcu_lock); /* - * Keep alive delay in us. based on 'power on clock', - * therefore in usec + * To avoid false wake, we enable beacon miss interrupt only + * when we go to sleep. We save the current interrupt mask + * so we can restore it after the system wakes up */ - set = KAL_DELAY * 1000; - REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set); + sc->wow_intr_before_sleep = ah->imask; + ah->imask &= ~ATH9K_INT_GLOBAL; + ath9k_hw_disable_interrupts(ah); + ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL; + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); - /* - * Create keep alive pattern to respond to beacons - */ - ath9k_wow_create_keep_alive_pattern(ah); + spin_unlock_bh(&sc->sc_pcu_lock); /* - * Configure MAC WoW Registers + * we can now sync irq and kill any running tasklets, since we already + * disabled interrupts and not holding a spin lock */ - set = 0; - /* Send keep alive timeouts anyway */ - clr = AR_WOW_KEEP_ALIVE_AUTO_DIS; + synchronize_irq(sc->irq); + tasklet_kill(&sc->intr_tq); - if (pattern_enable & AH_WOW_LINK_CHANGE) - wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL; - else - set = AR_WOW_KEEP_ALIVE_FAIL_DIS; + ath9k_hw_wow_enable(ah, triggers); - set = AR_WOW_KEEP_ALIVE_FAIL_DIS; - REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr); + ath9k_ps_restore(sc); + ath_dbg(common, WOW, "Suspend with WoW triggers: 0x%x\n", triggers); - /* - * we are relying on a bmiss failure. ensure we have - * enough threshold to prevent false positives - */ - REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, - AR_WOW_BMISSTHRESHOLD); + set_bit(ATH_OP_WOW_ENABLED, &common->op_flags); +fail_wow: + mutex_unlock(&sc->mutex); + return ret; +} - set = 0; - clr = 0; +int ath9k_resume(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + u8 status; - if (pattern_enable & AH_WOW_BEACON_MISS) { - set = AR_WOW_BEACON_FAIL_EN; - wow_event_mask |= AR_WOW_BEACON_FAIL; - } else { - clr = AR_WOW_BEACON_FAIL_EN; - } + mutex_lock(&sc->mutex); - REG_RMW(ah, AR_WOW_BCN_EN, set, clr); + ath9k_ps_wakeup(sc); - set = 0; - clr = 0; - /* - * Enable the magic packet registers - */ - if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) { - set = AR_WOW_MAGIC_EN; - wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND; - } else { - clr = AR_WOW_MAGIC_EN; - } - set |= AR_WOW_MAC_INTR_EN; - REG_RMW(ah, AR_WOW_PATTERN, set, clr); + spin_lock_bh(&sc->sc_pcu_lock); - REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B, - AR_WOW_PATTERN_SUPPORTED); + ath9k_hw_disable_interrupts(ah); + ah->imask = sc->wow_intr_before_sleep; + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); - /* - * Set the power states appropriately and enable PME - */ - clr = 0; - set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN | - AR_PMCTRL_PWR_PM_CTRL_ENA; + spin_unlock_bh(&sc->sc_pcu_lock); - clr = AR_PCIE_PM_CTRL_ENA; - REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr); + status = ath9k_hw_wow_wakeup(ah); + ath_dbg(common, WOW, "Resume with WoW status: 0x%x\n", status); - /* - * this is needed to prevent the chip waking up - * the host within 3-4 seconds with certain - * platform/BIOS. The fix is to enable - * D1 & D3 to match original definition and - * also match the OTP value. Anyway this - * is more related to SW WOW. - */ - clr = AR_PMCTRL_PWR_STATE_D1D3; - REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); + ath_restart_work(sc); + ath9k_start_btcoex(sc); + + clear_bit(ATH_OP_WOW_ENABLED, &common->op_flags); + + ath9k_ps_restore(sc); + mutex_unlock(&sc->mutex); + + return 0; +} - set = AR_PMCTRL_PWR_STATE_D1D3_REAL; - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); +void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + mutex_lock(&sc->mutex); + device_set_wakeup_enable(sc->dev, enabled); + mutex_unlock(&sc->mutex); + + ath_dbg(common, WOW, "WoW wakeup source is %s\n", + (enabled) ? "enabled" : "disabled"); +} + +void ath9k_init_wow(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; - REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); + if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow) { + if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565_11_OR_LATER(ah)) + hw->wiphy->wowlan = &ath9k_wowlan_support; + else + hw->wiphy->wowlan = &ath9k_wowlan_support_legacy; - /* to bring down WOW power low margin */ - set = BIT(13); - REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set); - /* HW WoW */ - clr = BIT(5); - REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr); + device_init_wakeup(sc->dev, 1); + } +} + +void ath9k_deinit_wow(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; - ath9k_hw_set_powermode_wow_sleep(ah); - ah->wow_event_mask = wow_event_mask; + if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow) + device_init_wakeup(sc->dev, 0); } -EXPORT_SYMBOL(ath9k_hw_wow_enable); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index c59ae43b9b35..0ac9212e42f7 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -34,6 +34,12 @@ #define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2) #define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18) +/* Shifts in ar5008_phy.c and ar9003_phy.c are equal for all revisions */ +#define ATH9K_PWRTBL_11NA_OFDM_SHIFT 0 +#define ATH9K_PWRTBL_11NG_OFDM_SHIFT 4 +#define ATH9K_PWRTBL_11NA_HT_SHIFT 8 +#define ATH9K_PWRTBL_11NG_HT_SHIFT 12 + static u16 bits_per_symbol[][2] = { /* 20MHz 40MHz */ @@ -47,26 +53,27 @@ static u16 bits_per_symbol[][2] = { { 260, 540 }, /* 7: 64-QAM 5/6 */ }; -#define IS_HT_RATE(_rate) ((_rate) & 0x80) - static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, struct sk_buff *skb); static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - int tx_flags, struct ath_txq *txq); + int tx_flags, struct ath_txq *txq, + struct ieee80211_sta *sta); static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, struct ath_txq *txq, struct list_head *bf_q, + struct ieee80211_sta *sta, struct ath_tx_status *ts, int txok); static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, struct list_head *head, bool internal); static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, int nframes, int nbad, int txok); -static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, - int seqno); +static void ath_tx_update_baw(struct ath_atx_tid *tid, struct ath_buf *bf); static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, struct sk_buff *skb); +static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ath_tx_control *txctl); enum { MCS_HT20, @@ -79,21 +86,27 @@ enum { /* Aggregation logic */ /*********************/ -void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq) - __acquires(&txq->axq_lock) +static void ath_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) { - spin_lock_bh(&txq->axq_lock); -} + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = info->status.status_driver_data[0]; -void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq) - __releases(&txq->axq_lock) -{ - spin_unlock_bh(&txq->axq_lock); + if (info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS | + IEEE80211_TX_STATUS_EOSP)) { + ieee80211_tx_status_skb(hw, skb); + return; + } + + if (sta) + ieee80211_tx_status_noskb(hw, sta, info); + + dev_kfree_skb(skb); } void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) __releases(&txq->axq_lock) { + struct ieee80211_hw *hw = sc->hw; struct sk_buff_head q; struct sk_buff *skb; @@ -102,53 +115,169 @@ void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) spin_unlock_bh(&txq->axq_lock); while ((skb = __skb_dequeue(&q))) - ieee80211_tx_status(sc->hw, skb); + ath_tx_status(hw, skb); } -static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) +void ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_atx_ac *ac = tid->ac; - - if (tid->paused) - return; + struct ieee80211_txq *queue = + container_of((void *)tid, struct ieee80211_txq, drv_priv); - if (tid->sched) - return; + ieee80211_schedule_txq(sc->hw, queue); +} - tid->sched = true; - list_add_tail(&tid->list, &ac->tid_q); +void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv; + struct ath_txq *txq = tid->txq; - if (ac->sched) - return; + ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n", + queue->sta ? queue->sta->addr : queue->vif->addr, + tid->tidno); - ac->sched = true; - list_add_tail(&ac->list, &txq->axq_acq); + ath_txq_lock(sc, txq); + ath_txq_schedule(sc, txq); + ath_txq_unlock(sc, txq); } static struct ath_frame_info *get_frame_info(struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); BUILD_BUG_ON(sizeof(struct ath_frame_info) > - sizeof(tx_info->rate_driver_data)); - return (struct ath_frame_info *) &tx_info->rate_driver_data[0]; + sizeof(tx_info->status.status_driver_data)); + return (struct ath_frame_info *) &tx_info->status.status_driver_data[0]; } static void ath_send_bar(struct ath_atx_tid *tid, u16 seqno) { + if (!tid->an->sta) + return; + ieee80211_send_bar(tid->an->vif, tid->an->sta->addr, tid->tidno, seqno << IEEE80211_SEQ_SEQ_SHIFT); } +static bool ath_merge_ratetbl(struct ieee80211_sta *sta, struct ath_buf *bf, + struct ieee80211_tx_info *tx_info) +{ + struct ieee80211_sta_rates *ratetbl; + u8 i; + + if (!sta) + return false; + + ratetbl = rcu_dereference(sta->rates); + if (!ratetbl) + return false; + + if (tx_info->control.rates[0].idx < 0 || + tx_info->control.rates[0].count == 0) + { + i = 0; + } else { + bf->rates[0] = tx_info->control.rates[0]; + i = 1; + } + + for ( ; i < IEEE80211_TX_MAX_RATES; i++) { + bf->rates[i].idx = ratetbl->rate[i].idx; + bf->rates[i].flags = ratetbl->rate[i].flags; + if (tx_info->control.use_rts) + bf->rates[i].count = ratetbl->rate[i].count_rts; + else if (tx_info->control.use_cts_prot) + bf->rates[i].count = ratetbl->rate[i].count_cts; + else + bf->rates[i].count = ratetbl->rate[i].count; + } + + return true; +} + static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ath_buf *bf) { - ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates, - ARRAY_SIZE(bf->rates)); + struct ieee80211_tx_info *tx_info; + + tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); + + if (!ath_merge_ratetbl(sta, bf, tx_info)) + ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates, + ARRAY_SIZE(bf->rates)); +} + +static void ath_txq_skb_done(struct ath_softc *sc, struct sk_buff *skb) +{ + struct ath_frame_info *fi = get_frame_info(skb); + struct ath_txq *txq; + int q = fi->txq; + + if (q < 0) + return; + + txq = sc->tx.txq_map[q]; + if (WARN_ON(--txq->pending_frames < 0)) + txq->pending_frames = 0; + +} + +static struct ath_atx_tid * +ath_get_skb_tid(struct ath_node *an, struct sk_buff *skb) +{ + u8 tidno = skb->priority & IEEE80211_QOS_CTL_TID_MASK; + return ATH_AN_2_TID(an, tidno); +} + +static int +ath_tid_pull(struct ath_atx_tid *tid, struct sk_buff **skbuf) +{ + struct ieee80211_txq *txq = container_of((void*)tid, struct ieee80211_txq, drv_priv); + struct ath_softc *sc = tid->an->sc; + struct ieee80211_hw *hw = sc->hw; + struct ath_tx_control txctl = { + .txq = tid->txq, + .sta = tid->an->sta, + }; + struct sk_buff *skb; + struct ath_frame_info *fi; + int q, ret; + + skb = ieee80211_tx_dequeue(hw, txq); + if (!skb) + return -ENOENT; + + ret = ath_tx_prepare(hw, skb, &txctl); + if (ret) { + ieee80211_free_txskb(hw, skb); + return ret; + } + + q = skb_get_queue_mapping(skb); + if (tid->txq == sc->tx.txq_map[q]) { + fi = get_frame_info(skb); + fi->txq = q; + ++tid->txq->pending_frames; + } + + *skbuf = skb; + return 0; +} + +static int ath_tid_dequeue(struct ath_atx_tid *tid, + struct sk_buff **skb) +{ + int ret = 0; + *skb = __skb_dequeue(&tid->retry_q); + if (!*skb) + ret = ath_tid_pull(tid, skb); + + return ret; } static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = tid->ac->txq; + struct ath_txq *txq = tid->txq; struct sk_buff *skb; struct ath_buf *bf; struct list_head bf_head; @@ -160,27 +289,22 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) memset(&ts, 0, sizeof(ts)); - while ((skb = __skb_dequeue(&tid->buf_q))) { + while ((skb = __skb_dequeue(&tid->retry_q))) { fi = get_frame_info(skb); bf = fi->bf; - if (!bf) { - bf = ath_tx_setup_buffer(sc, txq, tid, skb); - if (!bf) { - ieee80211_free_txskb(sc->hw, skb); - continue; - } + ath_txq_skb_done(sc, skb); + ieee80211_free_txskb(sc->hw, skb); + continue; } - if (fi->retries) { - list_add_tail(&bf->list, &bf_head); - ath_tx_update_baw(sc, tid, bf->bf_state.seqno); - ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); + if (fi->baw_tracked) { + ath_tx_update_baw(tid, bf); sendbar = true; - } else { - ath_set_rates(tid->an->vif, tid->an->sta, bf); - ath_tx_send_normal(sc, txq, NULL, skb); } + + list_add_tail(&bf->list, &bf_head); + ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); } if (sendbar) { @@ -190,11 +314,15 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) } } -static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, - int seqno) +static void ath_tx_update_baw(struct ath_atx_tid *tid, struct ath_buf *bf) { + struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); + u16 seqno = bf->bf_state.seqno; int index, cindex; + if (!fi->baw_tracked) + return; + index = ATH_BA_INDEX(tid->seq_start, seqno); cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); @@ -208,14 +336,19 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, } } -static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid, - u16 seqno) +static void ath_tx_addto_baw(struct ath_atx_tid *tid, struct ath_buf *bf) { + struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); + u16 seqno = bf->bf_state.seqno; int index, cindex; + if (fi->baw_tracked) + return; + index = ATH_BA_INDEX(tid->seq_start, seqno); cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); __set_bit(cindex, tid->tx_buf); + fi->baw_tracked = 1; if (index >= ((tid->baw_tail - tid->baw_head) & (ATH_TID_MAX_BUFS - 1))) { @@ -224,12 +357,6 @@ static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid, } } -/* - * TODO: For frame(s) that are in the retry state, we will reuse the - * sequence number(s) without setting the retry bit. The - * alternative is to give up on these and BAR the receiver's window - * forward. - */ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid) @@ -243,24 +370,18 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, memset(&ts, 0, sizeof(ts)); INIT_LIST_HEAD(&bf_head); - while ((skb = __skb_dequeue(&tid->buf_q))) { + while (ath_tid_dequeue(tid, &skb) == 0) { fi = get_frame_info(skb); bf = fi->bf; if (!bf) { - ath_tx_complete(sc, skb, ATH_TX_ERROR, txq); + ath_tx_complete(sc, skb, ATH_TX_ERROR, txq, NULL); continue; } list_add_tail(&bf->list, &bf_head); - - ath_tx_update_baw(sc, tid, bf->bf_state.seqno); - ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); } - - tid->seq_next = tid->seq_start; - tid->baw_tail = tid->baw_head; - tid->bar_index = -1; } static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, @@ -271,7 +392,7 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, struct ieee80211_hdr *hdr; int prev = fi->retries; - TX_STAT_INC(txq->axq_qnum, a_retries); + TX_STAT_INC(sc, txq->axq_qnum, a_retries); fi->retries += count; if (prev > 0) @@ -323,15 +444,14 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf) tbf->bf_buf_addr = bf->bf_buf_addr; memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len); tbf->bf_state = bf->bf_state; + tbf->bf_state.stale = false; return tbf; } -static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_status *ts, int txok, - int *nframes, int *nbad) +static void ath_tx_count_frames(struct ath_buf *bf, struct ath_tx_status *ts, + int txok, int *nframes, int *nbad) { - struct ath_frame_info *fi; u16 seq_st = 0; u32 ba[WME_BA_BMP_SIZE >> 5]; int ba_index; @@ -341,13 +461,14 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, *nframes = 0; isaggr = bf_isaggr(bf); + memset(ba, 0, WME_BA_BMP_SIZE >> 3); + if (isaggr) { seq_st = ts->ts_seqnum; - memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3); + memcpy(ba, &ts->ba, WME_BA_BMP_SIZE >> 3); } while (bf) { - fi = get_frame_info(bf->bf_mpdu); ba_index = ATH_BA_INDEX(seq_st, bf->bf_state.seqno); (*nframes)++; @@ -361,15 +482,13 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf, struct list_head *bf_q, + struct ieee80211_sta *sta, + struct ath_atx_tid *tid, struct ath_tx_status *ts, int txok) { struct ath_node *an = NULL; struct sk_buff *skb; - struct ieee80211_sta *sta; - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_hdr *hdr; struct ieee80211_tx_info *tx_info; - struct ath_atx_tid *tid = NULL; struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; struct list_head bf_head; struct sk_buff_head bf_pending; @@ -380,14 +499,11 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ieee80211_tx_rate rates[4]; struct ath_frame_info *fi; int nframes; - u8 tidno; bool flush = !!(ts->ts_status & ATH9K_TX_FLUSH); int i, retries; int bar_index = -1; skb = bf->bf_mpdu; - hdr = (struct ieee80211_hdr *)skb->data; - tx_info = IEEE80211_SKB_CB(skb); memcpy(rates, bf->rates, sizeof(rates)); @@ -396,20 +512,15 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, for (i = 0; i < ts->ts_rateindex; i++) retries += rates[i].count; - rcu_read_lock(); - - sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2); if (!sta) { - rcu_read_unlock(); - INIT_LIST_HEAD(&bf_head); while (bf) { bf_next = bf->bf_next; - if (!bf->bf_stale || bf_next != NULL) + if (!bf->bf_state.stale || bf_next != NULL) list_move_tail(&bf->list, &bf_head); - ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0); + ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, ts, 0); bf = bf_next; } @@ -417,8 +528,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, } an = (struct ath_node *)sta->drv_priv; - tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; - tid = ATH_AN_2_TID(an, tidno); seq_first = tid->seq_start; isba = ts->ts_flags & ATH9K_TX_BA; @@ -430,7 +539,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * Only BlockAcks have a TID and therefore normal Acks cannot be * checked */ - if (isba && tidno != ts->tid) + if (isba && tid->tidno != ts->tid) txok = false; isaggr = bf_isaggr(bf); @@ -439,12 +548,12 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (isaggr && txok) { if (ts->ts_flags & ATH9K_TX_BA) { seq_st = ts->ts_seqnum; - memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3); + memcpy(ba, &ts->ba, WME_BA_BMP_SIZE >> 3); } else { /* * AR5416 can become deaf/mute when BA * issue happens. Chip needs to be reset. - * But AP code may have sychronization issues + * But AP code may have synchronization issues * when perform internal reset in this routine. * Only enable reset in STA mode for now. */ @@ -455,7 +564,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, __skb_queue_head_init(&bf_pending); - ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad); + ath_tx_count_frames(bf, ts, txok, &nframes, &nbad); while (bf) { u16 seqno = bf->bf_state.seqno; @@ -466,7 +575,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, tx_info = IEEE80211_SKB_CB(skb); fi = get_frame_info(skb); - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) { + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno) || + !tid->active) { /* * Outside of the current BlockAck window, * maybe part of a previous session @@ -499,7 +609,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * not a holding desc. */ INIT_LIST_HEAD(&bf_head); - if (bf_next != NULL || !bf_last->bf_stale) + if (bf_next != NULL || !bf_last->bf_state.stale) list_move_tail(&bf->list, &bf_head); if (!txpending) { @@ -507,15 +617,19 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * complete the acked-ones/xretried ones; update * block-ack window */ - ath_tx_update_baw(sc, tid, seqno); + ath_tx_update_baw(tid, bf); if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { memcpy(tx_info->control.rates, rates, sizeof(rates)); ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok); rc_update = false; + if (bf == bf->bf_lastbf) + ath_dynack_sample_tx_ts(sc->sc_ah, + bf->bf_mpdu, + ts, sta); } - ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, + ath_tx_complete_buf(sc, bf, txq, &bf_head, sta, ts, !txfail); } else { if (tx_info->flags & IEEE80211_TX_STATUS_EOSP) { @@ -523,7 +637,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ieee80211_sta_eosp(sta); } /* retry the un-acked ones */ - if (bf->bf_next == NULL && bf_last->bf_stale) { + if (bf->bf_next == NULL && bf_last->bf_state.stale) { struct ath_buf *tbf; tbf = ath_clone_txbuf(sc, bf_last); @@ -533,10 +647,11 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * run out of tx buf. */ if (!tbf) { - ath_tx_update_baw(sc, tid, seqno); + ath_tx_update_baw(tid, bf); ath_tx_complete_buf(sc, bf, txq, - &bf_head, ts, 0); + &bf_head, NULL, ts, + 0); bar_index = max_t(int, bar_index, ATH_BA_INDEX(seq_first, seqno)); break; @@ -560,12 +675,11 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (an->sleeping) ieee80211_sta_set_buffered(sta, tid->tidno, true); - skb_queue_splice(&bf_pending, &tid->buf_q); + skb_queue_splice_tail(&bf_pending, &tid->retry_q); if (!an->sleeping) { - ath_tx_queue_tid(txq, tid); - + ath_tx_queue_tid(sc, tid); if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) - tid->ac->clear_ps_filter = true; + tid->clear_ps_filter = true; } } @@ -580,8 +694,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ath_txq_lock(sc, txq); } - rcu_read_unlock(); - if (needreset) ath9k_queue_reset(sc, RESET_TYPE_TX_ERROR); } @@ -592,11 +704,33 @@ static bool bf_is_ampdu_not_probing(struct ath_buf *bf) return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); } +static void ath_tx_count_airtime(struct ath_softc *sc, + struct ieee80211_sta *sta, + struct ath_buf *bf, + struct ath_tx_status *ts, + u8 tid) +{ + u32 airtime = 0; + int i; + + airtime += ts->duration * (ts->ts_longretry + 1); + for(i = 0; i < ts->ts_rateindex; i++) { + int rate_dur = ath9k_hw_get_duration(sc->sc_ah, bf->bf_desc, i); + airtime += rate_dur * bf->rates[i].count; + } + + ieee80211_sta_register_airtime(sta, tid, airtime, 0); +} + static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, struct ath_tx_status *ts, struct ath_buf *bf, struct list_head *bf_head) { + struct ieee80211_hw *hw = sc->hw; struct ieee80211_tx_info *info; + struct ieee80211_sta *sta; + struct ieee80211_hdr *hdr; + struct ath_atx_tid *tid = NULL; bool txok, flush; txok = !(ts->ts_status & ATH9K_TXERR_MASK); @@ -607,18 +741,33 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, if (bf_is_ampdu_not_probing(bf)) txq->axq_ampdu_depth--; + ts->duration = ath9k_hw_get_duration(sc->sc_ah, bf->bf_desc, + ts->ts_rateindex); + + hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; + sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2); + if (sta) { + struct ath_node *an = (struct ath_node *)sta->drv_priv; + tid = ath_get_skb_tid(an, bf->bf_mpdu); + ath_tx_count_airtime(sc, sta, bf, ts, tid->tidno); + if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) + tid->clear_ps_filter = true; + } + if (!bf_isampdu(bf)) { if (!flush) { info = IEEE80211_SKB_CB(bf->bf_mpdu); memcpy(info->control.rates, bf->rates, sizeof(info->control.rates)); ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); + ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts, + sta); } - ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok); + ath_tx_complete_buf(sc, bf, txq, bf_head, sta, ts, txok); } else - ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok); + ath_tx_complete_aggr(sc, txq, bf, bf_head, sta, tid, ts, txok); - if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) && !flush) + if (!flush) ath_txq_schedule(sc, txq); } @@ -652,7 +801,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct ieee80211_tx_rate *rates; u32 max_4ms_framelen, frmlen; u16 aggr_limit, bt_aggr_limit, legacy = 0; - int q = tid->ac->txq->mac80211_qnum; + int q = tid->txq->mac80211_qnum; int i; skb = bf->bf_mpdu; @@ -705,11 +854,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, if (bt_aggr_limit) aggr_limit = bt_aggr_limit; - /* - * h/w can accept aggregates up to 16 bit lengths (65535). - * The IE, however can hold up to 65536, which shows up here - * as zero. Ignore 65536 since we are constrained by hw. - */ if (tid->an->maxampdu) aggr_limit = min(aggr_limit, tid->an->maxampdu); @@ -790,37 +934,73 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, return ndelim; } -static struct ath_buf * +static int ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid) + struct ath_atx_tid *tid, struct ath_buf **buf) { + struct ieee80211_tx_info *tx_info; struct ath_frame_info *fi; - struct sk_buff *skb; struct ath_buf *bf; + struct sk_buff *skb, *first_skb = NULL; u16 seqno; + int ret; while (1) { - skb = skb_peek(&tid->buf_q); - if (!skb) - break; + ret = ath_tid_dequeue(tid, &skb); + if (ret < 0) + return ret; fi = get_frame_info(skb); bf = fi->bf; if (!fi->bf) bf = ath_tx_setup_buffer(sc, txq, tid, skb); + else + bf->bf_state.stale = false; if (!bf) { - __skb_unlink(skb, &tid->buf_q); + ath_txq_skb_done(sc, skb); ieee80211_free_txskb(sc->hw, skb); continue; } + bf->bf_next = NULL; + bf->bf_lastbf = bf; + + tx_info = IEEE80211_SKB_CB(skb); + tx_info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | + IEEE80211_TX_STATUS_EOSP); + + /* + * No aggregation session is running, but there may be frames + * from a previous session or a failed attempt in the queue. + * Send them out as normal data frames + */ + if (!tid->active) + tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU; + + if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) { + bf->bf_state.bf_type = 0; + break; + } + bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR; seqno = bf->bf_state.seqno; /* do not step over block-ack window */ - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) - break; + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) { + __skb_queue_tail(&tid->retry_q, skb); + + /* If there are other skbs in the retry q, they are + * probably within the BAW, so loop immediately to get + * one of them. Otherwise the queue can get stuck. */ + if (!skb_queue_is_first(&tid->retry_q, skb) && + !WARN_ON(skb == first_skb)) { + if(!first_skb) /* infinite loop prevention */ + first_skb = skb; + continue; + } + return -EINPROGRESS; + } if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) { struct ath_tx_status ts = {}; @@ -828,73 +1008,55 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, INIT_LIST_HEAD(&bf_head); list_add(&bf->list, &bf_head); - __skb_unlink(skb, &tid->buf_q); - ath_tx_update_baw(sc, tid, seqno); - ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); + ath_tx_update_baw(tid, bf); + ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); continue; } - bf->bf_next = NULL; - bf->bf_lastbf = bf; - return bf; + if (bf_isampdu(bf)) + ath_tx_addto_baw(tid, bf); + + break; } - return NULL; + *buf = bf; + return 0; } -static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, - struct ath_txq *txq, - struct ath_atx_tid *tid, - struct list_head *bf_q, - int *aggr_len) +static int +ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid, struct list_head *bf_q, + struct ath_buf *bf_first) { #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) - struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL; - int rl = 0, nframes = 0, ndelim, prev_al = 0; + struct ath_buf *bf = bf_first, *bf_prev = NULL; + int nframes = 0, ndelim, ret; u16 aggr_limit = 0, al = 0, bpad = 0, - al_delta, h_baw = tid->baw_size / 2; - enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; + al_delta, h_baw = tid->baw_size / 2; struct ieee80211_tx_info *tx_info; struct ath_frame_info *fi; struct sk_buff *skb; - do { - bf = ath_tx_get_tid_subframe(sc, txq, tid); - if (!bf) { - status = ATH_AGGR_BAW_CLOSED; - break; - } + bf = bf_first; + aggr_limit = ath_lookup_rate(sc, bf, tid); + + while (bf) + { skb = bf->bf_mpdu; fi = get_frame_info(skb); - if (!bf_first) - bf_first = bf; - - if (!rl) { - ath_set_rates(tid->an->vif, tid->an->sta, bf); - aggr_limit = ath_lookup_rate(sc, bf, tid); - rl = 1; - } - /* do not exceed aggregation limit */ al_delta = ATH_AGGR_DELIM_SZ + fi->framelen; - - if (nframes && - ((aggr_limit < (al + bpad + al_delta + prev_al)) || - ath_lookup_legacy(bf))) { - status = ATH_AGGR_LIMITED; - break; - } - - tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); - if (nframes && (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) - break; - - /* do not exceed subframe limit */ - if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) { - status = ATH_AGGR_LIMITED; - break; + if (nframes) { + if (aggr_limit < al + bpad + al_delta || + ath_lookup_legacy(bf) || nframes >= h_baw) + goto stop; + + tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); + if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) || + !(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) + goto stop; } /* add padding for previous frame to aggregation length */ @@ -912,22 +1074,33 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, bf->bf_next = NULL; /* link buffers of this frame to the aggregate */ - if (!fi->retries) - ath_tx_addto_baw(sc, tid, bf->bf_state.seqno); bf->bf_state.ndelim = ndelim; - __skb_unlink(skb, &tid->buf_q); list_add_tail(&bf->list, bf_q); if (bf_prev) bf_prev->bf_next = bf; bf_prev = bf; - } while (!skb_queue_empty(&tid->buf_q)); + ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf); + if (ret < 0) + break; + } + goto finish; +stop: + __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); +finish: + bf = bf_first; + bf->bf_lastbf = bf_prev; - *aggr_len = al; + if (bf == bf_prev) { + al = get_frame_info(bf->bf_mpdu)->framelen; + bf->bf_state.bf_type = BUF_AMPDU; + } else { + TX_STAT_INC(sc, txq->axq_qnum, a_aggr); + } - return status; + return al; #undef PADBYTES } @@ -937,8 +1110,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, * width - 0 for 20 MHz, 1 for 40 MHz * half_gi - to use 4us v/s 3.6 us for symbol time */ -static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen, - int width, int half_gi, bool shortPreamble) +u32 ath_pkt_duration(u8 rix, int pktlen, int width, + int half_gi, bool shortPreamble) { u32 nbits, nsymbits, duration, nsymbols; int streams; @@ -966,11 +1139,11 @@ static int ath_max_framelen(int usec, int mcs, bool ht40, bool sgi) int symbols, bits; int bytes = 0; + usec -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); symbols = sgi ? TIME_SYMBOLS_HALFGI(usec) : TIME_SYMBOLS(usec); bits = symbols * bits_per_symbol[mcs % 8][ht40] * streams; bits -= OFDM_PLCP_BITS; bytes = bits / 8; - bytes -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); if (bytes > 65532) bytes = 65532; @@ -998,16 +1171,104 @@ void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop) } } +static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, + u8 rateidx, bool is_40, bool is_cck, bool is_mcs) +{ + u8 max_power; + struct sk_buff *skb; + struct ath_frame_info *fi; + struct ieee80211_tx_info *info; + struct ath_hw *ah = sc->sc_ah; + bool is_2ghz, is_5ghz, use_stbc; + + if (sc->tx99_state || !ah->tpc_enabled) + return MAX_RATE_POWER; + + skb = bf->bf_mpdu; + fi = get_frame_info(skb); + info = IEEE80211_SKB_CB(skb); + + is_2ghz = info->band == NL80211_BAND_2GHZ; + is_5ghz = info->band == NL80211_BAND_5GHZ; + use_stbc = is_mcs && rateidx < 8 && (info->flags & + IEEE80211_TX_CTL_STBC); + + if (is_mcs) + rateidx += is_5ghz ? ATH9K_PWRTBL_11NA_HT_SHIFT + : ATH9K_PWRTBL_11NG_HT_SHIFT; + else if (is_2ghz && !is_cck) + rateidx += ATH9K_PWRTBL_11NG_OFDM_SHIFT; + else + rateidx += ATH9K_PWRTBL_11NA_OFDM_SHIFT; + + if (!AR_SREV_9300_20_OR_LATER(ah)) { + int txpower = fi->tx_power; + + if (is_40) { + u8 power_ht40delta; + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + u16 eeprom_rev = ah->eep_ops->get_eeprom_rev(ah); + + if (eeprom_rev >= AR5416_EEP_MINOR_VER_2) { + struct modal_eep_header *pmodal; + + pmodal = &eep->modalHeader[is_2ghz]; + power_ht40delta = pmodal->ht40PowerIncForPdadc; + } else { + power_ht40delta = 2; + } + txpower += power_ht40delta; + } + + if (AR_SREV_9287(ah) || AR_SREV_9285(ah) || + AR_SREV_9271(ah)) { + txpower -= 2 * AR9287_PWR_TABLE_OFFSET_DB; + } else if (AR_SREV_9280_20_OR_LATER(ah)) { + s8 power_offset; + + power_offset = ah->eep_ops->get_eeprom(ah, + EEP_PWR_TABLE_OFFSET); + txpower -= 2 * power_offset; + } + + if (OLC_FOR_AR9280_20_LATER(ah) && is_cck) + txpower -= 2; + + txpower = max(txpower, 0); + max_power = min_t(u8, ah->tx_power[rateidx], txpower); + + /* XXX: clamp minimum TX power at 1 for AR9160 since if + * max_power is set to 0, frames are transmitted at max + * TX power + */ + if (!max_power && !AR_SREV_9280_20_OR_LATER(ah)) + max_power = 1; + } else if (!bf->bf_state.bfs_paprd) { + if (use_stbc) + max_power = min_t(u8, ah->tx_power_stbc[rateidx], + fi->tx_power); + else + max_power = min_t(u8, ah->tx_power[rateidx], + fi->tx_power); + } else { + max_power = ah->paprd_training_power; + } + + return max_power; +} + static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_info *info, int len) + struct ath_tx_info *info, int len, bool rts) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct sk_buff *skb; struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rates; const struct ieee80211_rate *rate; struct ieee80211_hdr *hdr; struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); + u32 rts_thresh = sc->hw->wiphy->rts_threshold; int i; u8 rix = 0; @@ -1021,16 +1282,26 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, info->rtscts_rate = fi->rtscts_rate; for (i = 0; i < ARRAY_SIZE(bf->rates); i++) { - bool is_40, is_sgi, is_sp; + bool is_40, is_sgi, is_sp, is_cck; int phy; if (!rates[i].count || (rates[i].idx < 0)) - continue; + break; rix = rates[i].idx; info->rates[i].Tries = rates[i].count; - if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) { + /* + * Handle RTS threshold for unaggregated HT frames. + */ + if (bf_isampdu(bf) && !bf_isaggr(bf) && + (rates[i].flags & IEEE80211_TX_RC_MCS) && + unlikely(rts_thresh != (u32) -1)) { + if (!rts_thresh || (len > rts_thresh)) + rts = true; + } + + if (rts || rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) { info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; info->flags |= ATH9K_TXDESC_RTSENA; } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { @@ -1052,16 +1323,24 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, info->rates[i].Rate = rix | 0x80; info->rates[i].ChSel = ath_txchainmask_reduction(sc, ah->txchainmask, info->rates[i].Rate); - info->rates[i].PktDuration = ath_pkt_duration(sc, rix, len, + info->rates[i].PktDuration = ath_pkt_duration(rix, len, is_40, is_sgi, is_sp); if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC; + if (rix >= 8 && fi->dyn_smps) { + info->rates[i].RateFlags |= + ATH9K_RATESERIES_RTS_CTS; + info->flags |= ATH9K_TXDESC_CTSENA; + } + + info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, + is_40, false, true); continue; } /* legacy rates */ - rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx]; - if ((tx_info->band == IEEE80211_BAND_2GHZ) && + rate = &common->sbands[tx_info->band].bitrates[rates[i].idx]; + if ((tx_info->band == NL80211_BAND_2GHZ) && !(rate->flags & IEEE80211_RATE_ERP_G)) phy = WLAN_RC_PHY_CCK; else @@ -1083,6 +1362,10 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah, phy, rate->bitrate * 100, len, rix, is_sp); + + is_cck = IS_CCK_RATE(info->rates[i].Rate); + info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, false, + is_cck, false); } /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ @@ -1123,11 +1406,12 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf, struct ath_hw *ah = sc->sc_ah; struct ath_buf *bf_first = NULL; struct ath_tx_info info; + u32 rts_thresh = sc->hw->wiphy->rts_threshold; + bool rts = false; memset(&info, 0, sizeof(info)); info.is_first = true; info.is_last = true; - info.txpower = MAX_RATE_POWER; info.qcu = txq->axq_qnum; while (bf) { @@ -1140,12 +1424,13 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf, if (bf->bf_next) info.link = bf->bf_next->bf_daddr; else - info.link = 0; + info.link = (sc->tx99_state) ? bf->bf_daddr : 0; if (!bf_first) { bf_first = bf; - info.flags = ATH9K_TXDESC_INTREQ; + if (!sc->tx99_state) + info.flags = ATH9K_TXDESC_INTREQ; if ((tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) || txq == sc->tx.uapsdq) info.flags |= ATH9K_TXDESC_CLRDMASK; @@ -1159,7 +1444,26 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf, info.flags |= (u32) bf->bf_state.bfs_paprd << ATH9K_TXDESC_PAPRD_S; - ath_buf_set_rate(sc, bf, &info, len); + /* + * mac80211 doesn't handle RTS threshold for HT because + * the decision has to be taken based on AMPDU length + * and aggregation is done entirely inside ath9k. + * Set the RTS/CTS flag for the first subframe based + * on the threshold. + */ + if (aggr && (bf == bf_first) && + unlikely(rts_thresh != (u32) -1)) { + /* + * "len" is the size of the entire AMPDU. + */ + if (!rts_thresh || (len > rts_thresh)) + rts = true; + } + + if (!aggr) + len = fi->framelen; + + ath_buf_set_rate(sc, bf, &info, len, rts); } info.buf_addr[0] = bf->bf_buf_addr; @@ -1188,96 +1492,133 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf, } } -static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid) +static void +ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid, struct list_head *bf_q, + struct ath_buf *bf_first) { - struct ath_buf *bf; - enum ATH_AGGR_STATUS status; - struct ieee80211_tx_info *tx_info; - struct list_head bf_q; - int aggr_len; + struct ath_buf *bf = bf_first, *bf_prev = NULL; + int nframes = 0, ret; do { - if (skb_queue_empty(&tid->buf_q)) - return; + struct ieee80211_tx_info *tx_info; - INIT_LIST_HEAD(&bf_q); + nframes++; + list_add_tail(&bf->list, bf_q); + if (bf_prev) + bf_prev->bf_next = bf; + bf_prev = bf; - status = ath_tx_form_aggr(sc, txq, tid, &bf_q, &aggr_len); + if (nframes >= 2) + break; - /* - * no frames picked up to be aggregated; - * block-ack window is not open. - */ - if (list_empty(&bf_q)) + ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf); + if (ret < 0) break; - bf = list_first_entry(&bf_q, struct ath_buf, list); - bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list); tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); - - if (tid->ac->clear_ps_filter) { - tid->ac->clear_ps_filter = false; - tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; - } else { - tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT; + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { + __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); + break; } - /* if only one frame, send as non-aggregate */ - if (bf == bf->bf_lastbf) { - aggr_len = get_frame_info(bf->bf_mpdu)->framelen; - bf->bf_state.bf_type = BUF_AMPDU; - } else { - TX_STAT_INC(txq->axq_qnum, a_aggr); - } + ath_set_rates(tid->an->vif, tid->an->sta, bf); + } while (1); +} + +static int ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, + struct ath_atx_tid *tid) +{ + struct ath_buf *bf = NULL; + struct ieee80211_tx_info *tx_info; + struct list_head bf_q; + int aggr_len = 0, ret; + bool aggr; + + INIT_LIST_HEAD(&bf_q); + + ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf); + if (ret < 0) + return ret; + + tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); + aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); + if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || + (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { + __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); + return -EBUSY; + } - ath_tx_fill_desc(sc, bf, txq, aggr_len); - ath_tx_txqaddbuf(sc, txq, &bf_q, false); - } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH && - status != ATH_AGGR_BAW_CLOSED); + ath_set_rates(tid->an->vif, tid->an->sta, bf); + if (aggr) + aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf); + else + ath_tx_form_burst(sc, txq, tid, &bf_q, bf); + + if (list_empty(&bf_q)) + return -EAGAIN; + + if (tid->clear_ps_filter || tid->an->no_ps_filter) { + tid->clear_ps_filter = false; + tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; + } + + ath_tx_fill_desc(sc, bf, txq, aggr_len); + ath_tx_txqaddbuf(sc, txq, &bf_q, false); + return 0; } int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_atx_tid *txtid; + struct ath_txq *txq; struct ath_node *an; u8 density; + ath_dbg(common, XMIT, "%s called\n", __func__); + an = (struct ath_node *)sta->drv_priv; txtid = ATH_AN_2_TID(an, tid); + txq = txtid->txq; + + ath_txq_lock(sc, txq); /* update ampdu factor/density, they may have changed. This may happen * in HT IBSS when a beacon with HT-info is received after the station * has already been added. */ - if (sta->ht_cap.ht_supported) { - an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + - sta->ht_cap.ampdu_factor); - density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); + if (sta->deflink.ht_cap.ht_supported) { + an->maxampdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + + sta->deflink.ht_cap.ampdu_factor)) - 1; + density = ath9k_parse_mpdudensity(sta->deflink.ht_cap.ampdu_density); an->mpdudensity = density; } txtid->active = true; - txtid->paused = true; *ssn = txtid->seq_start = txtid->seq_next; txtid->bar_index = -1; memset(txtid->tx_buf, 0, sizeof(txtid->tx_buf)); txtid->baw_head = txtid->baw_tail = 0; + ath_txq_unlock_complete(sc, txq); + return 0; } void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_node *an = (struct ath_node *)sta->drv_priv; struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); - struct ath_txq *txq = txtid->ac->txq; + struct ath_txq *txq = txtid->txq; + + ath_dbg(common, XMIT, "%s called\n", __func__); ath_txq_lock(sc, txq); txtid->active = false; - txtid->paused = true; ath_tx_flush_tid(sc, txtid); ath_txq_unlock_complete(sc, txq); } @@ -1285,86 +1626,65 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, struct ath_node *an) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_atx_tid *tid; - struct ath_atx_ac *ac; - struct ath_txq *txq; - bool buffered; int tidno; - for (tidno = 0, tid = &an->tid[tidno]; - tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { - - if (!tid->sched) - continue; - - ac = tid->ac; - txq = ac->txq; - - ath_txq_lock(sc, txq); - - buffered = !skb_queue_empty(&tid->buf_q); + ath_dbg(common, XMIT, "%s called\n", __func__); - tid->sched = false; - list_del(&tid->list); - - if (ac->sched) { - ac->sched = false; - list_del(&ac->list); - } + for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { + tid = ath_node_to_tid(an, tidno); - ath_txq_unlock(sc, txq); + if (!skb_queue_empty(&tid->retry_q)) + ieee80211_sta_set_buffered(sta, tid->tidno, true); - ieee80211_sta_set_buffered(sta, tidno, buffered); } } void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_atx_tid *tid; - struct ath_atx_ac *ac; struct ath_txq *txq; int tidno; - for (tidno = 0, tid = &an->tid[tidno]; - tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { + ath_dbg(common, XMIT, "%s called\n", __func__); - ac = tid->ac; - txq = ac->txq; + for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { + tid = ath_node_to_tid(an, tidno); + txq = tid->txq; ath_txq_lock(sc, txq); - ac->clear_ps_filter = true; - - if (!skb_queue_empty(&tid->buf_q) && !tid->paused) { - ath_tx_queue_tid(txq, tid); + tid->clear_ps_filter = true; + if (!skb_queue_empty(&tid->retry_q)) { + ath_tx_queue_tid(sc, tid); ath_txq_schedule(sc, txq); } - ath_txq_unlock_complete(sc, txq); + } } -void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, - u16 tidno) -{ - struct ath_atx_tid *tid; - struct ath_node *an; - struct ath_txq *txq; - an = (struct ath_node *)sta->drv_priv; - tid = ATH_AN_2_TID(an, tidno); - txq = tid->ac->txq; +static void +ath9k_set_moredata(struct ath_softc *sc, struct ath_buf *bf, bool val) +{ + struct ieee80211_hdr *hdr; + __le16 mask, mask_val; - ath_txq_lock(sc, txq); + mask = cpu_to_le16(IEEE80211_FCTL_MOREDATA); - tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; - tid->paused = false; + if (val) + mask_val = mask; + else + mask_val = 0; - if (!skb_queue_empty(&tid->buf_q)) { - ath_tx_queue_tid(txq, tid); - ath_txq_schedule(sc, txq); + hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; + if ((hdr->frame_control & mask) != mask_val) { + hdr->frame_control = (hdr->frame_control & ~mask) | mask_val; + dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, + sizeof(*hdr), DMA_TO_DEVICE); } - - ath_txq_unlock_complete(sc, txq); } void ath9k_release_buffered_frames(struct ieee80211_hw *hw, @@ -1378,9 +1698,8 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, struct ath_txq *txq = sc->tx.uapsdq; struct ieee80211_tx_info *info; struct list_head bf_q; - struct ath_buf *bf_tail = NULL, *bf; - int sent = 0; - int i; + struct ath_buf *bf_tail = NULL, *bf = NULL; + int i, ret; INIT_LIST_HEAD(&bf_q); for (i = 0; tids && nframes; i++, tids >>= 1) { @@ -1390,37 +1709,38 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, continue; tid = ATH_AN_2_TID(an, i); - if (tid->paused) - continue; - ath_txq_lock(sc, tid->ac->txq); - while (!skb_queue_empty(&tid->buf_q) && nframes > 0) { - bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid); - if (!bf) + ath_txq_lock(sc, tid->txq); + while (nframes > 0) { + ret = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, + tid, &bf); + if (ret < 0) break; - __skb_unlink(bf->bf_mpdu, &tid->buf_q); + ath9k_set_moredata(sc, bf, true); list_add_tail(&bf->list, &bf_q); ath_set_rates(tid->an->vif, tid->an->sta, bf); - ath_tx_addto_baw(sc, tid, bf->bf_state.seqno); - bf->bf_state.bf_type &= ~BUF_AGGR; + if (bf_isampdu(bf)) + bf->bf_state.bf_type &= ~BUF_AGGR; if (bf_tail) bf_tail->bf_next = bf; bf_tail = bf; nframes--; - sent++; - TX_STAT_INC(txq->axq_qnum, a_queued_hw); + TX_STAT_INC(sc, txq->axq_qnum, a_queued_hw); - if (skb_queue_empty(&tid->buf_q)) + if (an->sta && skb_queue_empty(&tid->retry_q)) ieee80211_sta_set_buffered(an->sta, i, false); } - ath_txq_unlock_complete(sc, tid->ac->txq); + ath_txq_unlock_complete(sc, tid->txq); } if (list_empty(&bf_q)) return; + if (!more_data) + ath9k_set_moredata(sc, bf_tail, false); + info = IEEE80211_SKB_CB(bf_tail->bf_mpdu); info->flags |= IEEE80211_TX_STATUS_EOSP; @@ -1494,7 +1814,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) txq->axq_link = NULL; __skb_queue_head_init(&txq->complete_q); INIT_LIST_HEAD(&txq->axq_q); - INIT_LIST_HEAD(&txq->axq_acq); spin_lock_init(&txq->axq_lock); txq->axq_depth = 0; txq->axq_ampdu_depth = 0; @@ -1538,20 +1857,13 @@ int ath_txq_update(struct ath_softc *sc, int qnum, int ath_cabq_update(struct ath_softc *sc) { struct ath9k_tx_queue_info qi; - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; int qnum = sc->beacon.cabq->axq_qnum; ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); - /* - * Ensure the readytime % is within the bounds. - */ - if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND) - sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND; - else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND) - sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND; - qi.tqi_readyTime = (cur_conf->beacon_interval * - sc->config.cabqReadytime) / 100; + qi.tqi_readyTime = (TU_TO_USEC(cur_conf->beacon_interval) * + ATH_CABQ_READY_TIME) / 100; ath_txq_update(sc, qnum, &qi); return 0; @@ -1571,7 +1883,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, while (!list_empty(list)) { bf = list_first_entry(list, struct ath_buf, list); - if (bf->bf_stale) { + if (bf->bf_state.stale) { list_del(&bf->list); ath_tx_return_buffer(sc, bf); @@ -1592,6 +1904,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, */ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq) { + rcu_read_lock(); ath_txq_lock(sc, txq); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { @@ -1610,6 +1923,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq) ath_drain_txq_list(sc, txq, &txq->axq_q); ath_txq_unlock_complete(sc, txq); + rcu_read_unlock(); } bool ath_drain_all_txq(struct ath_softc *sc) @@ -1620,7 +1934,7 @@ bool ath_drain_all_txq(struct ath_softc *sc) int i; u32 npend = 0; - if (test_bit(SC_OP_INVALID, &sc->sc_flags)) + if (test_bit(ATH_OP_INVALID, &common->op_flags)) return true; ath9k_hw_abort_tx_dma(ah); @@ -1630,24 +1944,24 @@ bool ath_drain_all_txq(struct ath_softc *sc) if (!ATH_TXQ_SETUP(sc, i)) continue; + if (!sc->tx.txq[i].axq_depth) + continue; + if (ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum)) npend |= BIT(i); } - if (npend) - ath_err(common, "Failed to stop TX DMA, queues=0x%03x!\n", npend); + if (npend) { + RESET_STAT_INC(sc, RESET_TX_DMA_ERROR); + ath_dbg(common, RESET, + "Failed to stop TX DMA, queues=0x%03x!\n", npend); + } for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (!ATH_TXQ_SETUP(sc, i)) continue; - /* - * The caller will resume queues with ieee80211_wake_queues. - * Mark the queue as not stopped to prevent ath_tx_complete - * from waking the queue too early. - */ txq = &sc->tx.txq[i]; - txq->stopped = false; ath_draintxq(sc, txq); } @@ -1660,63 +1974,60 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) sc->tx.txqsetup &= ~(1<<txq->axq_qnum); } -/* For each axq_acq entry, for each tid, try to schedule packets +/* For each acq entry, for each tid, try to schedule packets * for transmit until ampdu_depth has reached min Q depth. */ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) { - struct ath_atx_ac *ac, *ac_tmp, *last_ac; - struct ath_atx_tid *tid, *last_tid; + struct ieee80211_hw *hw = sc->hw; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ieee80211_txq *queue; + struct ath_atx_tid *tid; + int ret; + + if (txq->mac80211_qnum < 0) + return; - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags) || - list_empty(&txq->axq_acq) || - txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) return; + ieee80211_txq_schedule_start(hw, txq->mac80211_qnum); + spin_lock_bh(&sc->chan_lock); rcu_read_lock(); - ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); - last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list); + if (sc->cur_chan->stopped) + goto out; - list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { - last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list); - list_del(&ac->list); - ac->sched = false; + while ((queue = ieee80211_next_txq(hw, txq->mac80211_qnum))) { + bool force; - while (!list_empty(&ac->tid_q)) { - tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, - list); - list_del(&tid->list); - tid->sched = false; + tid = (struct ath_atx_tid *)queue->drv_priv; - if (tid->paused) - continue; + ret = ath_tx_sched_aggr(sc, txq, tid); + ath_dbg(common, QUEUE, "ath_tx_sched_aggr returned %d\n", ret); - ath_tx_sched_aggr(sc, txq, tid); + force = !skb_queue_empty(&tid->retry_q); + ieee80211_return_txq(hw, queue, force); + } - /* - * add tid to round-robin queue if more frames - * are pending for the tid - */ - if (!skb_queue_empty(&tid->buf_q)) - ath_tx_queue_tid(txq, tid); +out: + rcu_read_unlock(); + spin_unlock_bh(&sc->chan_lock); + ieee80211_txq_schedule_end(hw, txq->mac80211_qnum); +} - if (tid == last_tid || - txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) - break; - } +void ath_txq_schedule_all(struct ath_softc *sc) +{ + struct ath_txq *txq; + int i; - if (!list_empty(&ac->tid_q) && !ac->sched) { - ac->sched = true; - list_add_tail(&ac->list, &txq->axq_acq); - } + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + txq = sc->tx.txq_map[i]; - if (ac == last_ac || - txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) - break; + spin_lock_bh(&txq->axq_lock); + ath_txq_schedule(sc, txq); + spin_unlock_bh(&txq->axq_lock); } - - rcu_read_unlock(); } /***********/ @@ -1770,14 +2081,14 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, } if (puttxbuf) { - TX_STAT_INC(txq->axq_qnum, puttxbuf); + TX_STAT_INC(sc, txq->axq_qnum, puttxbuf); ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); ath_dbg(common, XMIT, "TXDP[%u] = %llx (%p)\n", txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); } - if (!edma) { - TX_STAT_INC(txq->axq_qnum, txstart); + if (!edma || sc->tx99_state) { + TX_STAT_INC(sc, txq->axq_qnum, txstart); ath9k_hw_txstart(ah, txq->axq_qnum); } @@ -1787,80 +2098,34 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, if (bf_is_ampdu_not_probing(bf)) txq->axq_ampdu_depth++; - bf = bf->bf_lastbf->bf_next; + bf_last = bf->bf_lastbf; + bf = bf_last->bf_next; + bf_last->bf_next = NULL; } } } -static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid, struct sk_buff *skb, - struct ath_tx_control *txctl) -{ - struct ath_frame_info *fi = get_frame_info(skb); - struct list_head bf_head; - struct ath_buf *bf; - - /* - * Do not queue to h/w when any of the following conditions is true: - * - there are pending frames in software queue - * - the TID is currently paused for ADDBA/BAR request - * - seqno is not within block-ack window - * - h/w queue depth exceeds low water mark - */ - if ((!skb_queue_empty(&tid->buf_q) || tid->paused || - !BAW_WITHIN(tid->seq_start, tid->baw_size, tid->seq_next) || - txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) && - txq != sc->tx.uapsdq) { - /* - * Add this frame to software queue for scheduling later - * for aggregation. - */ - TX_STAT_INC(txq->axq_qnum, a_queued_sw); - __skb_queue_tail(&tid->buf_q, skb); - if (!txctl->an || !txctl->an->sleeping) - ath_tx_queue_tid(txq, tid); - return; - } - - bf = ath_tx_setup_buffer(sc, txq, tid, skb); - if (!bf) { - ieee80211_free_txskb(sc->hw, skb); - return; - } - - ath_set_rates(tid->an->vif, tid->an->sta, bf); - bf->bf_state.bf_type = BUF_AMPDU; - INIT_LIST_HEAD(&bf_head); - list_add(&bf->list, &bf_head); - - /* Add sub-frame to BAW */ - ath_tx_addto_baw(sc, tid, bf->bf_state.seqno); - - /* Queue to h/w without aggregation */ - TX_STAT_INC(txq->axq_qnum, a_queued_hw); - bf->bf_lastbf = bf; - ath_tx_fill_desc(sc, bf, txq, fi->framelen); - ath_tx_txqaddbuf(sc, txq, &bf_head, false); -} - static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, struct sk_buff *skb) { + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_frame_info *fi = get_frame_info(skb); struct list_head bf_head; - struct ath_buf *bf; - - bf = fi->bf; + struct ath_buf *bf = fi->bf; INIT_LIST_HEAD(&bf_head); list_add_tail(&bf->list, &bf_head); bf->bf_state.bf_type = 0; + if (tid && (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) { + bf->bf_state.bf_type = BUF_AMPDU; + ath_tx_addto_baw(tid, bf); + } bf->bf_next = NULL; bf->bf_lastbf = bf; ath_tx_fill_desc(sc, bf, txq, fi->framelen); ath_tx_txqaddbuf(sc, txq, &bf_head, false); - TX_STAT_INC(txq->axq_qnum, queued); + TX_STAT_INC(sc, txq->axq_qnum, queued); } static void setup_frame_info(struct ieee80211_hw *hw, @@ -1876,6 +2141,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct ath_node *an = NULL; enum ath9k_key_type keytype; bool short_preamble = false; + u8 txpower; /* * We check if Short Preamble is needed for the CTS rate by @@ -1892,15 +2158,34 @@ static void setup_frame_info(struct ieee80211_hw *hw, if (sta) an = (struct ath_node *) sta->drv_priv; + if (tx_info->control.vif) { + struct ieee80211_vif *vif = tx_info->control.vif; + if (vif->bss_conf.txpower == INT_MIN) + goto nonvifpower; + txpower = 2 * vif->bss_conf.txpower; + } else { + struct ath_softc *sc; + nonvifpower: + sc = hw->priv; + + txpower = sc->cur_chan->cur_txpower; + } + memset(fi, 0, sizeof(*fi)); + fi->txq = -1; if (hw_key) fi->keyix = hw_key->hw_key_idx; else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0) fi->keyix = an->ps_key; else fi->keyix = ATH9K_TXKEYIX_INVALID; + fi->dyn_smps = sta && sta->deflink.smps_mode == IEEE80211_SMPS_DYNAMIC; fi->keytype = keytype; fi->framelen = framelen; + fi->tx_power = txpower; + + if (!rate) + return; fi->rtscts_rate = rate->hw_value; if (short_preamble) fi->rtscts_rate |= rate->hw_value_short; @@ -1911,8 +2196,7 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate) struct ath_hw *ah = sc->sc_ah; struct ath9k_channel *curchan = ah->curchan; - if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && - (curchan->channelFlags & CHANNEL_5GHZ) && + if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && IS_CHAN_5GHZ(curchan) && (chainmask == 0x7) && (rate < 0x90)) return 0x3; else if (AR_SREV_9462(ah) && ath9k_hw_btcoex_is_enabled(ah) && @@ -1946,7 +2230,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, ATH_TXBUF_RESET(bf); - if (tid) { + if (tid && ieee80211_is_data_present(hdr->frame_control)) { fragno = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; seqno = tid->seq_next; hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT); @@ -1978,6 +2262,28 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, return bf; } +void ath_assign_seq(struct ath_common *common, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = info->control.vif; + struct ath_vif *avp; + + if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) + return; + + if (!vif) + return; + + avp = (struct ath_vif *)vif->drv_priv; + + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + avp->seq_no += 0x10; + + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(avp->seq_no); +} + static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_tx_control *txctl) { @@ -1989,24 +2295,10 @@ static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, int frmlen = skb->len + FCS_LEN; int padpos, padsize; - /* NOTE: sta can be NULL according to net/mac80211.h */ - if (sta) - txctl->an = (struct ath_node *)sta->drv_priv; - if (info->control.hw_key) frmlen += info->control.hw_key->icv_len; - /* - * As a temporary workaround, assign seq# here; this will likely need - * to be cleaned up to work better with Beacon transmission and virtual - * BSSes. - */ - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - sc->tx.seq_no += 0x10; - hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); - } + ath_assign_seq(ath9k_hw_common(sc->sc_ah), skb); if ((vif && vif->type != NL80211_IFTYPE_AP && vif->type != NL80211_IFTYPE_AP_VLAN) || @@ -2033,23 +2325,24 @@ static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_tx_control *txctl) { - struct ieee80211_hdr *hdr; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = txctl->sta; struct ieee80211_vif *vif = info->control.vif; + struct ath_frame_info *fi = get_frame_info(skb); struct ath_softc *sc = hw->priv; struct ath_txq *txq = txctl->txq; struct ath_atx_tid *tid = NULL; + struct ath_node *an = NULL; struct ath_buf *bf; - u8 tidno; - int q; - int ret; + bool ps_resp; + int q, ret; + + ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE); ret = ath_tx_prepare(hw, skb, txctl); if (ret) return ret; - hdr = (struct ieee80211_hdr *) skb->data; /* * At this point, the vif, hw_key and sta pointers in the tx control * info are no longer valid (overwritten by the ath_frame_info data. @@ -2057,39 +2350,23 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, q = skb_get_queue_mapping(skb); - ath_txq_lock(sc, txq); - if (txq == sc->tx.txq_map[q] && - ++txq->pending_frames > sc->tx.txq_max_pending[q] && - !txq->stopped) { - ieee80211_stop_queue(sc->hw, q); - txq->stopped = true; - } - - if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) { - ath_txq_unlock(sc, txq); + if (ps_resp) txq = sc->tx.uapsdq; - ath_txq_lock(sc, txq); - } - if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) { - tidno = ieee80211_get_qos_ctl(hdr)[0] & - IEEE80211_QOS_CTL_TID_MASK; - tid = ATH_AN_2_TID(txctl->an, tidno); - - WARN_ON(tid->ac->txq != txctl->txq); + if (txctl->sta) { + an = (struct ath_node *) sta->drv_priv; + tid = ath_get_skb_tid(an, skb); } - if ((info->flags & IEEE80211_TX_CTL_AMPDU) && tid) { - /* - * Try aggregation if it's a unicast data frame - * and the destination is HT capable. - */ - ath_tx_send_ampdu(sc, txq, tid, skb, txctl); - goto out; + ath_txq_lock(sc, txq); + if (txq == sc->tx.txq_map[q]) { + fi->txq = q; + ++txq->pending_frames; } bf = ath_tx_setup_buffer(sc, txq, tid, skb); if (!bf) { + ath_txq_skb_done(sc, skb); if (txctl->paprd) dev_kfree_skb_any(skb); else @@ -2119,7 +2396,6 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, .txq = sc->beacon.cabq }; struct ath_tx_info info = {}; - struct ieee80211_hdr *hdr; struct ath_buf *bf_tail = NULL; struct ath_buf *bf; LIST_HEAD(bf_q); @@ -2127,8 +2403,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int max_duration; max_duration = - sc->cur_beacon_conf.beacon_interval * 1000 * - sc->cur_beacon_conf.dtim_period / ATH_BCBUF; + sc->cur_chan->beacon.beacon_interval * 1000 * + sc->cur_chan->beacon.dtim_period / ATH_BCBUF; do { struct ath_frame_info *fi = get_frame_info(skb); @@ -2142,7 +2418,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, bf->bf_lastbf = bf; ath_set_rates(vif, NULL, bf); - ath_buf_set_rate(sc, bf, &info, fi->framelen); + ath_buf_set_rate(sc, bf, &info, fi->framelen, false); duration += info.rates[0].PktDuration; if (bf_tail) bf_tail->bf_next = bf; @@ -2163,19 +2439,14 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (list_empty(&bf_q)) return; - bf = list_first_entry(&bf_q, struct ath_buf, list); - hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; - - if (hdr->frame_control & IEEE80211_FCTL_MOREDATA) { - hdr->frame_control &= ~IEEE80211_FCTL_MOREDATA; - dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, - sizeof(*hdr), DMA_TO_DEVICE); - } + bf = list_last_entry(&bf_q, struct ath_buf, list); + ath9k_set_moredata(sc, bf, false); + bf = list_first_entry(&bf_q, struct ath_buf, list); ath_txq_lock(sc, txctl.txq); ath_tx_fill_desc(sc, bf, txctl.txq, 0); ath_tx_txqaddbuf(sc, txctl.txq, &bf_q, false); - TX_STAT_INC(txctl.txq->axq_qnum, queued); + TX_STAT_INC(sc, txctl.txq->axq_qnum, queued); ath_txq_unlock(sc, txctl.txq); } @@ -2184,32 +2455,38 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, /*****************/ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - int tx_flags, struct ath_txq *txq) + int tx_flags, struct ath_txq *txq, + struct ieee80211_sta *sta) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; - int q, padpos, padsize; + int padpos, padsize; unsigned long flags; ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb); if (sc->sc_ah->caldata) - sc->sc_ah->caldata->paprd_packet_sent = true; + set_bit(PAPRD_PACKET_SENT, &sc->sc_ah->caldata->cal_flags); - if (!(tx_flags & ATH_TX_ERROR)) - /* Frame was ACKed */ - tx_info->flags |= IEEE80211_TX_STAT_ACK; + if (!(tx_flags & ATH_TX_ERROR)) { + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) + tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + else + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } - padpos = ieee80211_hdrlen(hdr->frame_control); - padsize = padpos & 3; - if (padsize && skb->len>padpos+padsize) { - /* - * Remove MAC header padding before giving the frame back to - * mac80211. - */ - memmove(skb->data + padsize, skb->data, padpos); - skb_pull(skb, padsize); + if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { + padpos = ieee80211_hdrlen(hdr->frame_control); + padsize = padpos & 3; + if (padsize && skb->len>padpos+padsize) { + /* + * Remove MAC header padding before giving the frame back to + * mac80211. + */ + memmove(skb->data + padsize, skb->data, padpos); + skb_pull(skb, padsize); + } } spin_lock_irqsave(&sc->sc_pm_lock, flags); @@ -2224,26 +2501,14 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, } spin_unlock_irqrestore(&sc->sc_pm_lock, flags); + ath_txq_skb_done(sc, skb); + tx_info->status.status_driver_data[0] = sta; __skb_queue_tail(&txq->complete_q, skb); - - q = skb_get_queue_mapping(skb); - if (txq == sc->tx.uapsdq) - txq = sc->tx.txq_map[q]; - - if (txq == sc->tx.txq_map[q]) { - if (WARN_ON(--txq->pending_frames < 0)) - txq->pending_frames = 0; - - if (txq->stopped && - txq->pending_frames < sc->tx.txq_max_pending[q]) { - ieee80211_wake_queue(sc->hw, q); - txq->stopped = false; - } - } } static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, struct ath_txq *txq, struct list_head *bf_q, + struct ieee80211_sta *sta, struct ath_tx_status *ts, int txok) { struct sk_buff *skb = bf->bf_mpdu; @@ -2259,6 +2524,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE); bf->bf_buf_addr = 0; + if (sc->tx99_state) + goto skip_tx_complete; if (bf->bf_state.bfs_paprd) { if (time_after(jiffies, @@ -2269,8 +2536,9 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, complete(&sc->paprd_complete); } else { ath_debug_stat_tx(sc, bf, ts, txq, tx_flags); - ath_tx_complete(sc, skb, tx_flags, txq); + ath_tx_complete(sc, skb, tx_flags, txq, sta); } +skip_tx_complete: /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't * accidentally reference it later. */ @@ -2284,6 +2552,16 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, spin_unlock_irqrestore(&sc->tx.txbuflock, flags); } +static void ath_clear_tx_status(struct ieee80211_tx_info *tx_info) +{ + void *ptr = &tx_info->status; + + memset(ptr + sizeof(tx_info->status.rates), 0, + sizeof(tx_info->status) - + sizeof(tx_info->status.rates) - + sizeof(tx_info->status.status_driver_data)); +} + static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, int nframes, int nbad, int txok) @@ -2295,6 +2573,8 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, struct ath_hw *ah = sc->sc_ah; u8 i, tx_rateindex; + ath_clear_tx_status(tx_info); + if (txok) tx_info->status.ack_signal = ts->ts_rssi; @@ -2309,6 +2589,13 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, tx_info->status.ampdu_len = nframes; tx_info->status.ampdu_ack_len = nframes - nbad; + tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1; + + for (i = tx_rateindex + 1; i < hw->max_rates; i++) { + tx_info->status.rates[i].count = 0; + tx_info->status.rates[i].idx = -1; + } + if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) == 0) { /* @@ -2330,13 +2617,6 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, tx_info->status.rates[tx_rateindex].count = hw->max_rate_tries; } - - for (i = tx_rateindex + 1; i < hw->max_rates; i++) { - tx_info->status.rates[i].count = 0; - tx_info->status.rates[i].idx = -1; - } - - tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1; } static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) @@ -2355,13 +2635,12 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ath_txq_lock(sc, txq); for (;;) { - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) break; if (list_empty(&txq->axq_q)) { txq->axq_link = NULL; - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) - ath_txq_schedule(sc, txq); + ath_txq_schedule(sc, txq); break; } bf = list_first_entry(&txq->axq_q, struct ath_buf, list); @@ -2375,7 +2654,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) * it with the STALE flag. */ bf_held = NULL; - if (bf->bf_stale) { + if (bf->bf_state.stale) { bf_held = bf; if (list_is_last(&bf_held->list, &txq->axq_q)) break; @@ -2392,14 +2671,14 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (status == -EINPROGRESS) break; - TX_STAT_INC(txq->axq_qnum, txprocdesc); + TX_STAT_INC(sc, txq->axq_qnum, txprocdesc); /* * Remove ath_buf's of the same transmit unit from txq, * however leave the last descriptor back as the holding * descriptor for hw. */ - lastbf->bf_stale = true; + lastbf->bf_state.stale = true; INIT_LIST_HEAD(&bf_head); if (!list_is_singular(&lastbf->list)) list_cut_position(&bf_head, @@ -2421,10 +2700,12 @@ void ath_tx_tasklet(struct ath_softc *sc) u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1) & ah->intr_txqs; int i; + rcu_read_lock(); for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) ath_tx_processq(sc, &sc->tx.txq[i]); } + rcu_read_unlock(); } void ath_tx_edma_tasklet(struct ath_softc *sc) @@ -2438,8 +2719,9 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) struct list_head *fifo_list; int status; + rcu_read_lock(); for (;;) { - if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) break; status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts); @@ -2454,6 +2736,13 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) if (ts.qid == sc->beacon.beaconq) { sc->beacon.tx_processed = true; sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK); + + if (ath9k_is_chanctx_enabled()) { + ath_chanctx_event(sc, NULL, + ATH_CHANCTX_EVENT_BEACON_SENT); + } + + ath9k_csa_update(sc); continue; } @@ -2461,16 +2750,16 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) ath_txq_lock(sc, txq); - TX_STAT_INC(txq->axq_qnum, txprocdesc); + TX_STAT_INC(sc, txq->axq_qnum, txprocdesc); fifo_list = &txq->txq_fifo[txq->txq_tailidx]; if (list_empty(fifo_list)) { ath_txq_unlock(sc, txq); - return; + break; } bf = list_first_entry(fifo_list, struct ath_buf, list); - if (bf->bf_stale) { + if (bf->bf_state.stale) { list_del(&bf->list); ath_tx_return_buffer(sc, bf); bf = list_first_entry(fifo_list, struct ath_buf, list); @@ -2492,7 +2781,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) ath_tx_txqaddbuf(sc, txq, &bf_q, true); } } else { - lastbf->bf_stale = true; + lastbf->bf_state.stale = true; if (bf != lastbf) list_cut_position(&bf_head, fifo_list, lastbf->list.prev); @@ -2501,6 +2790,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); ath_txq_unlock_complete(sc, txq); } + rcu_read_unlock(); } /*****************/ @@ -2557,8 +2847,6 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) return error; } - INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) error = ath_tx_edma_init(sc); @@ -2568,61 +2856,99 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) { struct ath_atx_tid *tid; - struct ath_atx_ac *ac; int tidno, acno; - for (tidno = 0, tid = &an->tid[tidno]; - tidno < IEEE80211_NUM_TIDS; - tidno++, tid++) { + for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { + tid = ath_node_to_tid(an, tidno); tid->an = an; tid->tidno = tidno; tid->seq_start = tid->seq_next = 0; tid->baw_size = WME_MAX_BA; tid->baw_head = tid->baw_tail = 0; - tid->sched = false; - tid->paused = false; tid->active = false; - __skb_queue_head_init(&tid->buf_q); + tid->clear_ps_filter = true; + __skb_queue_head_init(&tid->retry_q); + INIT_LIST_HEAD(&tid->list); acno = TID_TO_WME_AC(tidno); - tid->ac = &an->ac[acno]; - } + tid->txq = sc->tx.txq_map[acno]; - for (acno = 0, ac = &an->ac[acno]; - acno < IEEE80211_NUM_ACS; acno++, ac++) { - ac->sched = false; - ac->txq = sc->tx.txq_map[acno]; - INIT_LIST_HEAD(&ac->tid_q); + if (!an->sta) + break; /* just one multicast ath_atx_tid */ } } void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) { - struct ath_atx_ac *ac; struct ath_atx_tid *tid; struct ath_txq *txq; int tidno; - for (tidno = 0, tid = &an->tid[tidno]; - tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { + rcu_read_lock(); - ac = tid->ac; - txq = ac->txq; + for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { + tid = ath_node_to_tid(an, tidno); + txq = tid->txq; ath_txq_lock(sc, txq); - if (tid->sched) { - list_del(&tid->list); - tid->sched = false; - } - - if (ac->sched) { - list_del(&ac->list); - tid->ac->sched = false; - } + if (!list_empty(&tid->list)) + list_del_init(&tid->list); ath_tid_drain(sc, txq, tid); tid->active = false; ath_txq_unlock(sc, txq); + + if (!an->sta) + break; /* just one multicast ath_atx_tid */ } + + rcu_read_unlock(); } + +#ifdef CONFIG_ATH9K_TX99 + +int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb, + struct ath_tx_control *txctl) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ath_frame_info *fi = get_frame_info(skb); + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_buf *bf; + int padpos, padsize; + + padpos = ieee80211_hdrlen(hdr->frame_control); + padsize = padpos & 3; + + if (padsize && skb->len > padpos) { + if (skb_headroom(skb) < padsize) { + ath_dbg(common, XMIT, + "tx99 padding failed\n"); + return -EINVAL; + } + + skb_push(skb, padsize); + memmove(skb->data, skb->data + padsize, padpos); + } + + fi->keyix = ATH9K_TXKEYIX_INVALID; + fi->framelen = skb->len + FCS_LEN; + fi->keytype = ATH9K_KEY_TYPE_CLEAR; + + bf = ath_tx_setup_buffer(sc, txctl->txq, NULL, skb); + if (!bf) { + ath_dbg(common, XMIT, "tx99 buffer setup failed\n"); + return -EINVAL; + } + + ath_set_rates(sc->tx99_vif, NULL, bf); + + ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr); + ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum); + + ath_tx_send_normal(sc, txctl->txq, NULL, skb); + + return 0; +} + +#endif /* CONFIG_ATH9K_TX99 */ |
